2012-06-07 33 views
12

我想將一個Web服務URL請求表示爲一個對象,並發現有很多通用參數可能會在繼承層次結構中「冒泡」。一個請求可能有很多參數,一些必需的和其他可選的,我相信Bloch的Builder模式是一個不錯的選擇,它用流暢的接口模擬命名參數。具有繼承功能的構建模式

具體來說,我設計了谷歌地圖的Web服務API,具有一般的Web服務請求

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

serviceoutput是強制性的參數,並sensor強制參數。還有一個可選參數language

每項服務都有一組強制參數和可選參數。地理編碼服務有兩個可選參數,boundsregion。它還具有互斥的強制性參數,即addresslocation,它們指定服務的類型(分別爲直接或反向地理編碼)。我代表與新的兒童班互相排斥。

我想象中的類層次結構,例如:

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

如何創建一個使用的參數和方法,從生成器它所插入的類和超類?

回答

17

我正在根據https://stackoverflow.com/a/9138629/946814建立我的答案,但考慮到這種多層次的層次結構。

我們需要的是使用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... 
} 
+0

在具體類中重寫'getThis()'的實現不應該是抽象的。 – Eric

+0

@EricTobias你是對的,有複製粘貼的危險。固定。 –

+1

這太神奇了!正是我在找什麼! – Maddy