Ответ 1
Я строю свой ответ fooobar.com/info/172201/..., но рассматриваю эту многоуровневую иерархию.
Нам нужно реплицировать одну и ту же иерархию с внутренними классами Builder. Поскольку нам нужна цепочка методов, нам нужен метод getThis()
, который возвращает листовой объект иерархии. Чтобы передать свой тип вверх иерархии, родительские классы имеют общий T
, а лист связывает T
с самим собой.
Он обеспечивает безопасность типов и избегает любого выброса исключений из-за неинициализированных обязательных параметров или опечаток, а также приятного свободного интерфейса. Тем не менее, это очень дорогостоящий и сложный дизайн для представления такой простой структуры, как URL. Надеюсь, что это кому-то полезно - я предпочел конкатенацию строк в конце.
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:
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:
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...
}