2016-07-19 66 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