【发布时间】:2016-07-19 10:24:26
【问题描述】:
又是一天,又是与泛型的斗争。
我有一组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;
}
}
但令人惊讶的是,我得到了一些意想不到的结果。
例如,在下面的代码中,尽管C extends MultipleControl...
此外,以下build() 方法调用:new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder>("url", AutocompleteType.STANDARD).build()); 返回SimpleControl 而不是AutocompleteControl,这没有意义,因为我明确提供了类型参数。
最后一根稻草是我试图实现的简洁明了的代码被丑陋的new AutocompleteControlBuilder<AutocompleteControl, AutocompleteControlBuilder> 构造函数调用杀死了。有人能指出解决这个问题的最佳实践吗?
【问题讨论】:
-
请问您为什么有
builder字段?我没有看到你使用它。 Java 已经具有协变返回类型,乍一看,我会说您可以删除这两个类型参数,因为它们似乎都是实现细节。不过这真的取决于用途...... -
我有一个关于这个设置的快速问题@mr.nothing,你真的需要
SimpleControl是非抽象的吗? -
嗯,JavaFX 也是从构建器开始的,现在没有它们。所以建设者可能有风格上的缺陷。在您的情况下:更少的构造函数,控件类本身中的工厂方法(
RadioButton.create().label("not me").build():) -
@JornVernee,哦,你说得对,这段代码有点多余。将编辑问题,谢谢。关于第二个参数(控件相关)——我应该如何实现构建方法来返回正确的控件类型?
-
@EpicPandaForce,是的,这就是控件的组织方式。
标签: java generics inheritance fluent-interface