我知道堆栈溢出上有很多与此相关的变体和相关主题,但我还没有找到任何令人信服的答案,所以我自己尝试一下。
我正在尝试设计一个构建器工厂,它返回公共(public)构建器接口(interface)的不同子类。我希望允许所有实现共享一个公共(public)抽象类以供代码重用。
请注意,我对 build()
方法的返回类型不感兴趣,只对构建器的类型感兴趣。
这是我到目前为止所拥有的:
带有通用子接口(interface)的构建器接口(interface):
interface FruitBuilder<T extends FruitBuilder<T>> {
T taste(String taste);
T shape(String shape);
T weight(String weight);
Fruit build();
}
一些构建器还有其他方法:
interface GrapesBuilder extends FruitBuilder<GrapeBuilder> {
GrapesBuilder clusterSize(int clusterSize);
}
下一步是指定返回特定构建器的工厂:
interface FruitBuilderFactory {
GrapesBuilder grapes();
AppleBuilder apple();
LemonBuilder lemon();
}
这些界面的用户应该能够像这样使用它:
Fruit grapes = fruitBuilderFactory
.grapes()
.weight(4)
.color("Purple")
.clusterSize(4) // Note that the GrapesBuilder type must be accessible here!
.build();
大部分逻辑将进入抽象类,包括高级构建逻辑:
abstract class BaseFruitBuilder<T extends FruitBuilder<T>> implements FruitBuilder<T> {
String taste;
T taste(String taste) {
this.taste = taste;
return (T)this; // Ugly cast!!!!!
}
...
Fruit build() {
Fruit fruit = createSpecificInstance();
// Do a lot of stuff on the fruit instance.
return fruit;
}
protected abstract Fruit createSpecificInstance();
}
给定基类,实现新的构建器非常简单:
class GrapseBuilderImpl extends BaseFruitBuilder<GrapesBuilder> {
int clusterSize;
GrapesBuilder clusterSize(int clusterSize) {
this.clusterSize = clusterSize;
}
protected Fruit createSpecificInstance() {
return new Grape(clusterSize);
}
}
这一切都编译好了(至少是我真正的代码)。问题是我是否可以删除抽象类中对 T 的丑陋转换。
最佳答案
避免强制转换的一个选项是定义一个返回 T
的抽象方法。 :
abstract class BaseFruitBuilder<T extends FruitBuilder<T>> implements FruitBuilder<T> {
String taste;
T taste(String taste) {
this.taste = taste;
return returnThis();
}
protected abstract T returnThis();
//...
}
class GrapseBuilderImpl extends BaseFruitBuilder<GrapesBuilder> {
//...
@Override
protected T returnThis() {
return this;
}
}
缺点是您必须信任每个子类才能正确实现该方法。再说一次,按照你的方法,没有什么可以阻止任何人声明子类 GrapesBuilder extends BaseFruitBuilder<AppleBuilder>
,因此您需要在某种程度上信任子类。
编辑刚刚意识到这个解决方案被@user158037的comment引用。 。我自己也用过这个,但从未意识到这是一个众所周知的习语。 :-)
关于java - Builder Factory 返回不同的子接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32849499/