首先,我对 Java 比较陌生,所以我问的可能是微不足道的,但我在这里或其他地方找不到答案。
为简单起见,假设我有以下类层次结构:
class Shape {
protected Shape(double x, double y) {...}
}
class Circle extends Shape {
public Circle(double radius) {...}
}
class Rectangle extends Shape {
public Rectangle(double edge) {...}
}
我想为每个形状使用构建器模式。所以我为他们每个人都添加了构建器:
class Shape {
protected static abstract class BuilderBase<T extends BuilderBase<T, S>, S extends Shape> {
public T setLocation(double x, double y) {
// ...
return (T)this; // ? - is there a way to avoid this casting?
}
public abstract S build();
}
protected Shape(/*...*/) {/*...*/}
}
class Circle extends Shape {
public static class Builder extends BuilderBase<Builder, Circle> {
public Builder setRadius(double radius) {
//...
return this;
}
@Override
public Circle build() { return new Circle(/*...*/); }
}
private Circle(/*...*/) {/*...*/}
}
class Rectangle extends Shape {
public static class Builder extends BuilderBase<Builder, Rectangle> {
public Builder setRadius(double radius) {
//...
return this;
}
@Override
public Rectangle build() {
return new Rectangle(/*...*/);
}
}
public Rectangle(/*...*/) {/*...*/}
}
编辑: 这里使用泛型是为了允许以任何顺序使用 Builder 方法。例如,为了允许以下调用:
new Circle.Builder()
.setLocation(0, 0)
.setRadius(10)
.build();
我的问题出在这个转换中:
public T setLocation(double x, double y) {
// ...
return (T)this; // ? - is there a way to avoid this casting?
}
我正在努力寻找避免这种转换的方法。到目前为止我发现的唯一方法是向 BaseBuilder 方法添加另一个抽象方法:
protected static abstract class BuilderBase<T extends BuilderBase<T, S>, S extends Shape> {
protected abstract T getBuilder();
public T setLocation(double x, double y) {
// ...
return getBuilder();
}
//...
}
因此每个派生构建器都必须实现它:
@Override
protected Circle getBuilder() {
return this;
}
在我看来这有点矫枉过正,但我不想收到编译警告。
问题:有没有更优雅的方法来避免强制转换?
最佳答案
你无法避免为每个子类添加一些额外的代码,但你可以避免未经检查的强制转换。只需创建一个 abstract
方法,负责返回适当类型的 this
。此方法必须由具体子类实现一次,但可用于应返回 this
的基类的所有方法:
class Shape {
protected static abstract
class BuilderBase<T extends BuilderBase<T, S>, S extends Shape> {
/** all subclasses should implement {@code self()} as {@code return this;} */
abstract T self();
public T setLocation(double x, double y) {
// ...
return self();
}
public T setFooBar(FooBar x) {
// ...
return self();// the more methods you have the more useful self() becomes
}
public abstract S build();
}
protected Shape(/*...*/) {/*...*/}
}
class Circle extends Shape {
public static class Builder extends BuilderBase<Builder, Circle> {
@Override final Builder self() { return this; }
public Builder setRadius(double radius) {
//...
return this;
}
@Override
public Circle build() { return new Circle(/*...*/); }
}
private Circle(/*...*/) {/*...*/}
}
class Rectangle extends Shape {
public static class Builder extends BuilderBase<Builder, Rectangle> {
@Override final Builder self() { return this; }
public Builder setRadius(double radius) {
//...
return this;
}
@Override
public Rectangle build() {
return new Rectangle(/*...*/);
}
}
public Rectangle(/*...*/) {/*...*/}
}
关于Java builder 模式——抽象 builder ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27530750/