2012-06-07 2 views
12

웹 서비스 URL 요청을 객체로 나타내려고하고 상속 계층 구조에서 "부풀려 질 수있는"많은 공통 매개 변수가 있다는 것을 알았습니다. 요청에는 많은 매개 변수가있을 수 있으며, 일부 필수 및 기타 선택 사항이 있습니다. Bloch의 작성자 패턴은 유창한 인터페이스로 명명 된 인수를 에뮬레이션하는 좋은 옵션입니다.상속을 사용하는 작성자 패턴

특히, 나는 일반적으로 웹 서비스

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

serviceoutput 필수 인수입니다 요청 및 sensor 필수 매개 변수로이 Google지도 웹 서비스 API에 대한 설계하고있다. 선택적 매개 변수 language도 있습니다.

각 서비스에는 필수 및 선택적 매개 변수 집합이 있습니다. 지오 코드 서비스에는 두 개의 선택적 매개 변수 boundsregion이 있습니다. 또한 서비 스 유형 (각각 직접 또는 역 지오 코딩)을 지정하는 상호 배타적 인 필수 매개 변수 address 또는 location도 있습니다. 나는이 새로운 상호 배제를 새로운 어린이 수업으로 대표한다.

내가 같은 클래스 계층 구조를 상상 :

.-----. 
    | 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이지만이 다중 계층 구조를 고려하고 있습니다.

필요한 것은 빌더 내부 클래스로 동일한 계층 구조를 복제하는 것입니다. 메소드 연쇄를 원하기 때문에 계층 구조의 리프 객체를 반환하는 getThis() 메소드가 필요합니다. 상위 클래스의 유형을 상위 계층으로 전달하려면 T이라는 일반 클래스가 있고 리프는 자체에 T을 바인딩합니다.

형식 안전성을 보장하고 초기화되지 않은 필수 매개 변수 또는 오타 및 좋은 유창한 인터페이스로 인해 예외가 throw되는 것을 방지합니다. 그러나 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

관련 문제