2016-07-19 45 views
2

又一天又一次與泛型相沖突。在此樹是我想提供生成器,這些對象可以輕鬆創建Java流利的構建器和繼承

BaseControl 
|_SimpleControl 
    |_MultipleControl 
    |_AutocompleteControl 
    |_SelectControl 

對於每個非抽象的對象:

我已經設置Control對象具有以下繼承樹。以下是我迄今爲止:

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; 
    } 
} 

但令人驚訝的是,我得到了一些意想不到的結果。
例如,在下面的代碼我要投controlMultipleControl調用二傳手儘管C extends MultipleControl ...

此外,以下build()方法調用:new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>("url", AutocompleteType.STANDARD).build());回報SimpleControl代替AutocompleteControl不使感覺,因爲我明確提供了類型參數。

而最後一根稻草是我試圖實現的簡潔明瞭的代碼被醜陋的new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>構造函數調用所殺死。有人能指出我解決這個問題的最佳做法嗎?

+0

請問爲什麼你有''builder'''字段?我沒有看到你使用它。 Java已經有協變返回類型,乍一看,我可以說你可以刪除兩個類型參數,因爲它們都是實現細節。這真的取決於用途,雖然... –

+0

我有一個關於這個設置的快速問題@ mr.nothing,你真的需要'SimpleControl'是非抽象的嗎? – EpicPandaForce

+0

嗯,JavaFX也是以構建者開始的,現在沒有它們。所以建設者_can_有風格的缺點。在你的情況下:更少的構造函數,控制類本身的工廠方法('RadioButton.create()。label(「not me」))。build():') –

回答

1

好吧,爲了正確設置它,你應該做一些改變:

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; 
    } 
} 

因此,這意味着

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

這適用於MultipleControl extends SimpleControlAutocompleteControl extends MultipleControl,並且您具體的擴展名爲SimpleControl,可以用具體參數返回getThis()

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