生成器模式与继承 [英] Builder pattern with inheritance
问题描述
我想将一个Web服务URL请求表示为一个对象,并发现有许多常见参数可以在继承层次结构中冒泡。一个请求可能有很多参数,一些是必需的和其他可选的,我相信Bloch的Builder模式是一个很好的选择,用一个流畅的接口模拟命名参数。
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 request could have lots of parameters, some mandatory and other optional, for which I believe Bloch's Builder pattern is a nice option, emulating named arguments with a fluent interface.
具体,我正在设计Google Maps网络服务API,它具有一般的网络服务请求
Specifically, I'm designing for the Google Maps web service API, that has as general web service request
http://maps.googleapis.com/maps/api/service/output?{parameters}
service
和 output
是必需参数, sensor
是必需参数。还有一个可选参数 language
。
service
and output
are mandatory arguments, and sensor
a mandatory parameter. There is also an optional parameter language
.
每个服务都有一组强制性和可选参数.Geocode服务有两个可选参数, bounds
和区域
。它还具有互斥的强制性参数,地址
或位置
,用于指定服务类型(直接或反向地理编码,分别)。我用新的子课代表这种互斥。
Each service has its set of mandatory and optional parameters.The Geocode service has two optional parameters, bounds
and region
. It also has mutually exclusive mandatory parameters, address
or location
, that specify the type of service (direct or reverse geocoding, respectively). I represent this mutual exclusion with new children classes.
我想象类层次结构如下:
I imagine the class hierarchy as such:
.-----.
| Url |
'-----'
^
|
.---------.
| Request |
'---------'
^
|----------------------------+--------------...
.---------. .------------.
| Geocode | | Directions |
'---------' '------------'
^ ^
|------------+ .
.--------. .---------. .
| Direct | | Reverse | .
'--------' '---------'
然后,我想做类似以下的事情:
Then, I would like to do something like the following:
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();
如何创建一个使用类和插入它的超类中的参数和方法的构建器?
How can I create a Builder that uses arguments and methods from the class and superclasses in which it is inserted?
推荐答案
我正在建立我的答案 https://stackoverflow.com/a/9138629/946814 ,但考虑到这种多层次结构。
I'm building my answer upon https://stackoverflow.com/a/9138629/946814, but considering this multi-level hierarchy.
我们需要的是复制与Builder内部类相同的层次结构。由于我们需要方法链接,我们需要一个 getThis()
方法,它返回层次结构的叶对象。为了将其类型向上传递给层次结构,父类具有泛型 T
,并且叶子将 T
绑定到它本身。
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.
它确保了类型安全,并避免因未初始化的强制参数或拼写错误而导致的任何异常抛出,以及良好的流畅界面。然而,代表像URL这样简单的结构是一种非常昂贵和复杂的设计。我希望它对某人有用 - 我最后喜欢字符串连接。
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:
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 RequestUrl(Builder builder){
this.output = builder.output;
this.sensor = builder.sensor;
this.lang = builder.lang;
}
// other logic...
}
GeocodeRequestUrl:
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 GeocodeRequestUrl(Builder builder){
super (builder);
this.bounds = builder.bounds;
this.region = builder.region;
}
// other logic...
}
DirectGeocodeRequestUrl:
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:
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...
}
这篇关于生成器模式与继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!