2012-06-07 31 views
12

Tôi muốn đại diện cho yêu cầu URL dịch vụ web dưới dạng đối tượng và nhận thấy có rất nhiều tham số phổ biến có thể được "phát tán" trong hệ thống phân cấp thừa kế. Một yêu cầu có thể có nhiều tham số, một số tham số bắt buộc và tùy chọn khác, mà tôi tin rằng mẫu Builder của Bloch là một tùy chọn tốt, mô phỏng các đối số được đặt tên bằng giao diện thông thạo.Mô hình trình xây dựng có thừa kế

Cụ thể, tôi đang thiết kế cho Google Maps API dịch vụ web, mà đã là yêu cầu dịch vụ web chung

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

serviceoutput là đối số bắt buộc, và sensor một tham số bắt buộc. Ngoài ra còn có một tham số tùy chọn language.

Mỗi dịch vụ có bộ thông số bắt buộc và tùy chọn. Dịch vụ mã địa lý có hai tham số tùy chọn, boundsregion. Nó cũng có các thông số bắt buộc loại trừ lẫn nhau, address hoặc location, chỉ định loại dịch vụ (mã hóa địa lý trực tiếp hoặc ngược lại). Tôi đại diện cho loại trừ lẫn nhau này với các lớp trẻ em mới.

Tôi tưởng tượng hệ thống phân cấp lớp như vậy:

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

Sau đó, tôi muốn làm một cái gì đó như sau:

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

Làm thế nào tôi có thể tạo ra một Builder sử dụng lập luận và phương pháp từ lớp và siêu lớp mà nó được chèn vào?

Trả lời

17

Tôi đang xây dựng câu trả lời của mình theo số https://stackoverflow.com/a/9138629/946814, nhưng xem xét cấu trúc phân cấp đa cấp này.

Điều chúng tôi cần là nhân rộng cùng một hệ thống phân cấp với lớp bên trong Trình tạo. Khi chúng ta muốn chuỗi phương thức, chúng ta cần một phương thức getThis() trả về đối tượng lá của cấu trúc phân cấp. Để chuyển loại hệ thống phân cấp lên trên, các lớp cha có một số chung là T và lá tự liên kết với số T.

Đảm bảo an toàn loại và tránh bất kỳ trường hợp ngoại lệ nào do các tham số bắt buộc hoặc lỗi chính tả không bắt buộc, cộng với giao diện thông thạo tốt đẹp. Tuy nhiên, đó là một thiết kế rất tốn kém và phức tạp để thể hiện một cấu trúc đơn giản như một URL. Tôi hy vọng nó rất hữu ích cho ai đó - tôi thích chuỗi nối ở cuối.

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

Việc thực hiện ghi đè 'getThis()' trong các lớp cụ thể không được trừu tượng. – Eric

+0

@EricTobias Bạn nói đúng, nguy cơ sao chép-dán. Đã sửa. –

+1

Điều này thật tuyệt vời! Chính xác những gì tôi đang tìm kiếm! – Maddy