Builder pattern with inheritance

后端 未结 1 707
一向
一向 2021-02-01 08:10

I want to represent an web service URL request as an object, and found that there are lots of common parameters that could be \"bubbled up\" in an inheritance hierarchy. A reque

相关标签:
1条回答
  • 2021-02-01 08:19

    I'm building my answer upon https://stackoverflow.com/a/9138629/946814, but considering this multi-level hierarchy.

    What we need is to replicate the same hierarchy with the Builder inner classes. As we want method chaining, we need a getThis() method that returns the leaf object of the hierarchy. In order to pass its type upward the hierarchy, the parent classes have a generic T, and the leaf binds T to itself.

    It assures type-safety and avoids any exception throwing due to uninitialized mandatory parameters or typos, plus the nice fluent interface. However, it's a very costy and complex design to represent such a simple structure as an URL. I hope it is useful to someone - I preferred string concatenation at the end.

    RequestUrl:

    public abstract class RequestUrl{
        public static abstract class Builder<T extends Builder<T>>{
            protected String output;
            protected boolean sensor;
            //Optional parameters can have default values
            protected String lang = "en"; 
    
            public Builder(String output, boolean sensor){
                this.output = output;
                this.sensor = sensor;
            }
    
            public T lang(String lang){
                this.lang = lang;
                return getThis();
            }
    
            public abstract T getThis();
        }
    
        final private String output;
        final private boolean sensor;
        final private String lang;
    
        protected <T extends Builder<T>> RequestUrl(Builder<T> builder){
            this.output = builder.output;
            this.sensor = builder.sensor;
            this.lang = builder.lang;
        }
    
        // other logic...
    }
    

    GeocodeRequestUrl:

    public abstract class GeocodeRequestUrl extends RequestUrl {
        public static abstract class Builder<T extends Builder<T>>
            extends RequestUrl.Builder<Builder<T>>{
    
            protected Bounds bounds;
            protected String region = "us";
    
            public Builder(String output, boolean sensor){
                super( output, sensor );
            }
    
            public T bounds(Bounds bounds){
                this.bounds = bounds;
                return getThis();
            }
    
            public T region(String region){
                this.region = region;
                return getThis();
            }
    
            @Override
            public abstract T getThis();
        }
    
        final private Bounds bounds;
        final private String region;
    
        protected <T extends Builder<T>> GeocodeRequestUrl(Builder<T> builder){
            super (builder);
            this.bounds = builder.bounds;
            this.region = builder.region;
        }
    
        // other logic...
    }
    

    DirectGeocodeRequestUrl:

    public class DirectGeocodeRequestUrl extends GeocodeRequestUrl {
        public static class Builder<Builder>
            extends GeocodeRequestUrl.Builder<Builder>{
    
            protected String address;
    
            public Builder(String output, boolean sensor, String address){
                super( output, sensor );
                this.address = address;
            }
    
            @Override
            public Builder getThis(){
                return this;
            }
    
            public DirectGeocodeRequestUrl build(){
                return new DirectGeocodeRequestUrl(this);
            }
        }
    
        final private String address;
    
        protected DirectGeocodeRequestUrl(Builder builder){
            super (builder);
            this.address = builder.address;
        }
    
        // other logic...
    }
    

    ReverseGeocodeRequestUrl:

    public class ReverseGeocodeRequestUrl extends GeocodeRequestUrl {
        public static class Builder<Builder>
            extends GeocodeRequestUrl.Builder<Builder>{
    
            protected Coord location;
    
            public Builder(String output, boolean sensor, Coord location){
                super( output, sensor );
                this.location = location;
            }
    
            @Override
            public Builder getThis(){
                return this;
            }
    
            public ReverseGeocodeRequestUrl build(){
                return new ReverseGeocodeRequestUrl(this);
            }
        }
    
        final private Coord location;
    
        protected ReverseGeocodeRequestUrl(Builder builder){
            super (builder);
            this.location = builder.location;
        }
    
        // other logic...
    }
    
    0 讨论(0)
提交回复
热议问题