2016-07-19 7 views
2

제네릭에 대한 하루 하루 더 고투.Java 유창한 건축업자 및 상속

나는 다음과 같은 상속 트리 Control 객체로 설정 한 : 비 추상적 인 객체 각각에 대해

BaseControl 
|_SimpleControl 
    |_MultipleControl 
    |_AutocompleteControl 
    |_SelectControl 

을 내가 지금 이러한 개체를 쉽게 만들 수 있습니다 빌더를 제공하고자이 나무에. 여기에 지금까지 무엇을 가지고 :

BaseControlBuilder :

public abstract class BaseControlBuilder<C extends BaseControl, B extends BaseControlBuilder<C, B>> { 
    protected C control; 
    private B builder; 

    BaseControlBuilder() { 
     control = createObj(); 
     builder = getThis(); 
    } 
    public C build() { return control; } 

    protected abstract C createObj(); 
    protected abstract B getThis(); 
} 

SimpleControlBuilder :

public class SimpleControlBuilder<C extends SimpleControl, B extends SimpleControlBuilder<C, B>> 
     extends BaseControlBuilder<SimpleControl, SimpleControlBuilder<C, B>> { 

    public SimpleControlBuilder(final String id, final String caption, 
      final InputType controlType) { 
     super(); 
     control.setId(id); 
     control.setCaption(caption); 
     control.setType(controlType); 
    } 

    public SimpleControlBuilder(final InputType controlType) { 
     this("", "", controlType); 
    } 

    public SimpleControlBuilder(final Enum<?> en, final InputType controlType) { 
     this(en.name(), en.toString(), controlType); 
    } 

    public SimpleControlBuilder<C, B> disabled() { 
     control.setDisabled(true); 
     return this; 
    } 

    @Override 
    protected SimpleControl createObj() { 
     return new SimpleControl(); 
    } 

    @Override 
    protected SimpleControlBuilder<C, B> getThis() { 
     return this; 
    } 
} 

MultipleControlBuilder :

abstract class MultipleControlBuilder<C extends MultipleControl, B extends MultipleControlBuilder<C, B>> 
     extends SimpleControlBuilder<MultipleControl, MultipleControlBuilder<C, B>> { 

    MultipleControlBuilder(final InputType type) { 
     super(type); 
    } 

    MultipleControlBuilder(final String id, final String caption, 
      final InputType type) { 
     super(id, caption, type); 
    } 

    MultipleControlBuilder(final Enum<?> en, final InputType type) { 
     super(en, type); 
    } 

    public MultipleControlBuilder<C, B> multiple() { 
     ((MultipleControl) control).setMultiple(true); 
     return this; 
    } 
} 

AutocompleteControlBuilder :

public class AutocompleteControlBuilder<C extends AutocompleteControl, B extends AutocompleteControlBuilder<C, B>> 
    extends MultipleControlBuilder<AutocompleteControl, AutocompleteControlBuilder<C, B>> { 

    public AutocompleteControlBuilder(final String url, 
      final AutocompleteType autocompleteType) { 
     this("", "", url, autocompleteType); 
    } 

    public AutocompleteControlBuilder(final String id, 
      final String caption, final String url, 
      final AutocompleteType autocompleteType) { 
     super(id, caption, InputType.AUTOCOMPLETE); 
     ((AutocompleteControl) control).setAutocompleteUrl(url); 
     ((AutocompleteControl) control).setAutocompleteType(autocompleteType); 
    } 

    public AutocompleteControlBuilder(final Enum<?> en, final String url, 
      final AutocompleteType autocompleteType) { 
     this(en.name(), en.toString(), url, autocompleteType); 
    } 

    @Override 
    protected AutocompleteControl createObj() { 
     return new AutocompleteControl(); 
    } 

    @Override 
    protected AutocompleteControlBuilder<C, B> getThis() { 
     return this; 
    } 
} 

하지만 놀랍게도 예기치 않은 결과가 있습니다. 예를 들어
다음 코드에서 나는 사실에도 불구하고 세터를 호출 할 MultipleControlcontrol 캐스팅해야 그 또한 C extends MultipleControl ...

, 다음 build() 메서드 호출 : SimpleControl 대신 AutocompleteControlnew AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>("url", AutocompleteType.STANDARD).build()); 반환하지 않습니다 의미, 내가 명시 적으로 형식 매개 변수를 제공합니다.

마지막 빨대는 내가 달성하려고하는 간결함과 명확한 코드가 추한 new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder> 생성자 호출에 의해 사망합니다. 아무도이 문제를 해결하는 모범 사례를 가르쳐 줄 수 있습니까?

+0

나는'''builder''' 필드가있는 이유를 묻습니다. 나는 네가 그것을 사용하는 것을 보지 못한다. Java는 이미 covariant returns 유형을 가지고 있습니다. 언뜻보기에는 두 가지 유형 매개 변수를 모두 제거 할 수 있다고 말하고 싶습니다. 둘 다 구현 세부 사항 인 것처럼 보이기 때문입니다. 그것은 실제로 사용에 의존하지만 ... –

+0

이 설치에 대한 빠른 질문이 있습니다. mr.nothing, 당신은 실제로 'SimpleControl'이 아닌 추상이 필요합니까? – EpicPandaForce

+0

흠, JavaFX도 빌더와 함께 시작했으며 요즘에는 빌더가 없어도 마찬가지입니다. 따라서 건축업자들은 문체의 단점을 가지고 있습니다. 귀하의 경우 : 더 적은 생성자, 컨트롤 클래스 자체의 팩토리 메서드 ('RadioButton.create(). label ("not me").() :') –

답변

1

좋아, 올바르게 설정하기 위해, 당신은 몇 가지 변경해야 : 그래서

public abstract class SimpleControlBuilder<C extends SimpleControl, B extends SimpleControlBuilder<C, B>> 
     extends BaseControlBuilder<C, B> { 

    public SimpleControlBuilder(final String id, final String caption, 
      final InputType controlType) { 
     super(); 
     control.setId(id); 
     control.setCaption(caption); 
     control.setType(controlType); 
    } 

    public SimpleControlBuilder(final InputType controlType) { 
     this("", "", controlType); 
    } 

    public SimpleControlBuilder(final Enum<?> en, final InputType controlType) { 
     this(en.name(), en.toString(), controlType); 
    } 

    public B disabled() { 
     control.setDisabled(true); 
     return getThis(); 
    } 
} 

그리고

abstract class MultipleControlBuilder<C extends MultipleControl, B extends MultipleControlBuilder<C, B>> 
     extends SimpleControlBuilder<C, B> { 

    MultipleControlBuilder(final InputType type) { 
     super(type); 
    } 

    MultipleControlBuilder(final String id, final String caption, 
      final InputType type) { 
     super(id, caption, type); 
    } 

    MultipleControlBuilder(final Enum<?> en, final InputType type) { 
     super(en, type); 
    } 

    public B multiple() { 
     control.setMultiple(true); 
     return getThis(); 
    } 
} 

그리고

public abstract class AutocompleteControlBuilder<C extends AutocompleteControl, B extends AutocompleteControlBuilder<C, B>> 
    extends MultipleControlBuilder<C, B>> { 

    public AutocompleteControlBuilder(final String url, 
      final AutocompleteType autocompleteType) { 
     this("", "", url, autocompleteType); 
    } 

    public AutocompleteControlBuilder(final String id, 
      final String caption, final String url, 
      final AutocompleteType autocompleteType) { 
     super(id, caption, InputType.AUTOCOMPLETE); 
     control.setAutocompleteUrl(url); 
     control.setAutocompleteType(autocompleteType); 
    } 

    public AutocompleteControlBuilder(final Enum<?> en, final String url, 
      final AutocompleteType autocompleteType) { 
     this(en.name(), en.toString(), url, autocompleteType); 
    } 
} 
을 의미

public class SimpleControlBuilder<C extends SimpleControl, B extends SimpleControlBuilder<C, B>> 
     extends BaseControlBuilder<SimpleControl, SimpleControlBuilder<C, B>> { // this should extend with the extension classes 

    public SimpleControlBuilder(final String id, final String caption, 
      final InputType controlType) { 
     super(); 
     control.setId(id); 
     control.setCaption(caption); 
     control.setType(controlType); 
    } 

    public SimpleControlBuilder(final InputType controlType) { 
     this("", "", controlType); 
    } 

    public SimpleControlBuilder(final Enum<?> en, final InputType controlType) { 
     this(en.name(), en.toString(), controlType); 
    } 

    public SimpleControlBuilder<C, B> disabled() { // this should return B 
     control.setDisabled(true); 
     return this; 
    } 

    @Override 
    protected SimpleControl createObj() { // this should return C 
     return new SimpleControl(); 
    } 

    @Override 
    protected SimpleControlBuilder<C, B> getThis() { // this should return B 
     return this; 
    } 
} 

이 경우 MultipleControl extends SimpleControlAutocompleteControl extends MultipleControl이 있고 구체화 된 매개 변수를 사용하여 getThis()을 반환 할 수있는 SimpleControl의 구체적인 확장자가 있습니다.

public class SomeControlBuilder extends MultipleControlBuilder<SomeControl, SomeControlBuilder> { 
    public SomeControlBuilder(final InputType type) { 
     super(type); 
    } 

    public SomeControlBuilder(final String id, final String caption, 
      final InputType type) { 
     super(id, caption, type); 
    } 

    public SomeControlBuilder(final Enum<?> en, final InputType type) { 
     super(en, type); 
    } 

    @Override 
    protected SomeControlBuilder getThis() { 
     return this; 
    } 

    @Override 
    protected SomeControl createObj() { 
     return new SomeControl(); 
    } 
} 
+0

이 문제를 해결할 우아한 방법이 없다는 것을 알게 되었습니까? 논리적으로 생략 될 수있는 타입 매개 변수를 가진 여전히 끔찍한 생성자 호출이있을 것입니다. –

+0

글쎄, 나는 그 매개 변수들이하는 일을 정말로 모른다. 생성자를 유지한다면 계층 구조 전반에 걸쳐 3 개의 생성자를 유지해야 할 가능성이 높습니다 (예). 제네릭이 상당히 단순화되었다고 생각합니다. 꽤 우아하다고 생각합니다. – EpicPandaForce