首先,我对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) {...}
}
我想为每个形状使用构建器模式。所以我为每一个添加了Builders:
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(/*...*/) {/*...*/}
}
修改 这里使用Generic是为了允许以任何顺序使用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;
}
在我看来有点矫枉过正,但我不想得到编辑警告。
问题:有没有更优雅的方法来避免投射?
答案 0 :(得分:5)
您无法避免每个子类有一些额外的代码,但您可以避免使用未经检查的强制转换。只需创建一个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(/*...*/) {/*...*/}
}