我有一个生成器类,该类从大多数方法中返回以允许进行菊花链连接。为了与子类一起使用,我希望父方法返回子实例,以便子方法可以链接到末尾。
public class BaseBuilder<T extends BaseBuilder<T>> {
public T buildSomething() {
doSomeWork();
/* OPTION #1: */ return this; // "Type mismatch: cannot convert from BaseBuilder<T> to T"
/* OPTION #2: */ return T.this; // "Type mismatch: cannot convert from BaseBuilder<T> to T"
/* OPTION #3: */ return (T) this; // "Type safety: Unchecked cast from SqlBuilder<T> to T"
}
}
public class ChildBuilder extends BaseBuilder<ChildBuilder> {}
选项#1和#2导致编译错误,选项#3导致警告(尽管可以使用
@SuppressWarnings("unchecked")
禁止显示)。这里有更好的方法吗?如何安全地将Basebuilder转换为Childbuilder? 最佳答案
声明ChildBuilder extends BaseBuilder<ChildBuilder>
以某种方式指示代码气味,并且似乎违反了DRY。在此示例中,只能使用BaseBuilder
参数化ChildBuilder
,而不能使用其他参数设置参数,因此它应该是多余的。
我宁愿重新考虑是否真的要对此进行过度架构,并尝试将子代构建器中的所有方法放入BaseBuilder
中。然后,我可以简单地从所有支持链接的方法中返回this
。
如果我仍然认为将特定的构建器方法组分成自己的类将受益,那么我将优先考虑组合,因为不建议仅将继承应用于代码重用。
假设我们有BaseBuilder
的两个子类:
class BuilderA extends BaseBuilder<BuilderA> {
BuilderA buildSomethingA() { return this; }
}
class BuilderB extends BaseBuilder<BuilderB> {
BuilderB buildSomethingB() { return this; }
}
如果需要像这样将
buildSomethingA
和buildSomethingB
链接起来怎么办:builder.buildSomething().buildSomethingA().buildSomethingB();
如果不将子类方法移到
BaseBuilder
,我们将无法做到;但是想象一下还有BuilderC
,这些方法没有意义,并且不应从BaseBuilder
继承。如果我们仍然将这两个方法移到父类(super class),然后再将另外三个方法移到父类(super class),那么我们将最终得到一个父类(super class),该类负责整个层次结构中90%的职责,并提供大量代码,例如:
if ((this instanceof BuilderB) && !flag1 && flag2) {
...
} else if ((this instanceof BuilderC) && flag1 && !flag2 && thing != null) {
...
} else if ...
我更喜欢的解决方案是DSL:
builder.buildSomething1().buildSomething2()
.builderA()
.buildSomethingA1().buildSomethingA2()
.end()
.buildSomething3()
.builderB()
.buildSomethingB()
.end();
这里
end()
返回builder
实例,因此您可以链接更多的方法或启动新的子生成器。这样,(子)构建器可以继承其所需的内容(否则,它们只能扩展
BaseBuilder
),并可以具有自己有意义的层次结构或组成。