2012-06-07 19 views
12

Bir web hizmeti URL'sini bir nesne olarak temsil etmek istiyorum ve bir kalıtım hiyerarşisinde "köpürtülebilecek" birçok ortak parametrelerin bulunduğunu tespit ettim. Bir isteğin, bazı zorunlu ve diğer isteğe bağlı, çok sayıda parametresi olabilir. Bunun için Bloch's Builder modelinin iyi bir seçenek olduğunu ve akıcı bir arabirimle adlandırılmış argümanları taklit ettiğine inanıyorum.Kalıtım ile oluşturulacak desen kalıbı

Özellikle, genel web hizmeti

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

service ve output zorunlu argümanlar vardır istek ve sensor zorunlu parametre olarak sahip Google Haritalar web hizmeti API için tasarlıyorum. İsteğe bağlı language parametresi de vardır.

Her hizmetin zorunlu ve isteğe bağlı parametreleri vardır. Geocode hizmeti, bounds ve region olmak üzere iki isteğe bağlı parametreye sahiptir. Ayrıca, hizmet türünü (sırasıyla, doğrudan veya ters coğrafi kodlama) belirten, address veya location numaralı karşılıklı zorunlu parametrelere de sahiptir. Bu karşılıklı dışlamayı yeni çocuk sınıflarıyla temsil ediyorum.

ben gibi sınıf hiyerarşisi düşünün:

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

Sonra ben böyle bir şey yapmak istiyorum şu:

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(); 

ben den argümanlar ve yöntemler kullanan bir Oluşturucu nasıl oluşturabilirim eklendiği sınıf ve süper sınıflar?

cevap

17

https://stackoverflow.com/a/9138629/946814 numaralı telefondan yanıtımı yapıyorum, ancak bu çok düzeyli hiyerarşiyi göz önünde bulundurarak.

İhtiyacımız olan şey, aynı hiyerarşiyi Oluşturucu iç sınıflarıyla çoğaltmaktır. Yöntem zincirleme istediğimizden, hiyerarşinin yaprak nesnesini döndüren bir getThis() yöntemine ihtiyacımız var. Türünü hiyerarşiyi yukarı doğru geçirmek için, üst sınıflar genel bir T ve yaprak kendi başına T bağlar.

Bu, tür güvenliği sağlar ve başlatılmamış zorunlu parametreler veya yazım hataları ve ayrıca güzel akıcı arabirim nedeniyle herhangi bir istisna atmasını önler. Ancak, bu kadar basit bir yapıyı bir URL olarak temsil etmek çok masraflı ve karmaşık bir tasarım. Umarım birileri için yararlıdır - sonunda dizgi birleştirmeyi tercih ettim.

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... 
} 
+0

Beton sınıflarında getThis() 'in geçersiz kılınması soyut olmamalıdır. – Eric

+0

@EricTobias Haklısınız, bir kopya-yapıştır tehlikesi. Sabit. –

+1

Bu harika! Tam olarak aradığım şey! – Maddy