生成器模式与inheritance

我想将Web服务URL请求表示为对象,并发现有许多常见参数可以在inheritance层次结构中“冒泡”。 一个请求可能有很多参数,一些是强制的,另一些是可选的,我相信Bloch的Builder模式是一个很好的选择,用一个流畅的接口模拟命名参数。

具体来说,我正在设计Google Maps Web服务API,它具有一般的Web服务请求

http://maps.googleapis.com/maps/api/service/output?{parameters} 

serviceoutput是必需参数, sensor是必需参数。 还有一个可选的参数language

每个服务都有一组强制和可选参数.Geocode服务有两个可选参数, boundsregion 。 它还具有互斥的强制参数, addresslocation ,用于指定服务类型(分别为直接或反向地理编码)。 我用新的儿童class来代表这种相互排斥。

我想象类层次结构如下:

  .-----. | Url | '-----' ^ | .---------. | Request | '---------' ^ |----------------------------+--------------... .---------. .------------. | Geocode | | Directions | '---------' '------------' ^ ^ |------------+ . .--------. .---------. . | Direct | | Reverse | . '--------' '---------' 

然后,我想做类似以下的事情:

 String output = "xml"; boolean sensor = true; String address = "Av. Paulista, São Paulo, Brasil"; Bounds bounds = new Bounds(-20, -10, -25, -20); //Geographic rectangle String region = "br"; String lang = "pt-BR"; Coord location = new Coord(-12,-22); DirectGeocodeRequestUrl direct = new DirectGeocodeRequestUrl.Builder(output, sensor, address) .bounds(bounds) .language(lang) .build(); ReverseGeocodeRequestUrl reverse = new ReverseGeocodeRequestUrl.Builder(output, sensor, location) .language(lang) .region(region) .build(); 

如何创建一个使用类和插入它的超类中的参数和方法的构建器?

我正在https://stackoverflow.com/a/9138629/946814上建立我的答案,但考虑到这个多层次的层次结构。

我们需要的是使用Builder内部类复制相同的层次结构。 由于我们需要方法链接,我们需要一个getThis()方法来返回层次结构的叶对象。 为了将其类型向上传递给层次结构,父类具有通用T ,并且叶将T绑定到自身。

它确保了类型安全,并避免因未初始化的强制参数或拼写错误而导致的任何exception抛出,以及良好的流畅界面。 然而,代表像URL这样简单的结构是一种非常昂贵和复杂的设计。 我希望它对某些人有用 – 我最后喜欢字符串连接。

RequestUrl:

 public abstract class RequestUrl{ public static abstract class Builder>{ 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 RequestUrl(Builder 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> extends RequestUrl.Builder>{ 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 GeocodeRequestUrl(Builder builder){ super (builder); this.bounds = builder.bounds; this.region = builder.region; } // other logic... } 

DirectGeocodeRequestUrl:

 public class DirectGeocodeRequestUrl extends GeocodeRequestUrl { public static class Builder extends GeocodeRequestUrl.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 extends GeocodeRequestUrl.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... }