これは実行できますが、間違いなく実行する価値はありません。明白な実装...
class Shape
{
private final double opacity;
public double getOpacity()
{
return opacity;
}
public static abstract class Builder<T extends Shape> {
private double opacity;
public Builder<T> opacity(double opacity) {
this.opacity = opacity;
return this;
}
public abstract T build();
}
public static Builder<?> builder() {
return new Builder<Shape>()
{
@Override
public Shape build()
{
return new Shape(this);
}
};
}
protected Shape(Builder<?> builder) {
this.opacity = builder.opacity;
}
}
class Rectangle extends Shape {
private final double height;
private final double width;
public double getHeight()
{
return height;
}
public double getWidth()
{
return width;
}
public static abstract class Builder<T extends Rectangle> extends Shape.Builder<T> {
private double height;
private double width;
public Builder<T> height(double height) {
this.height = height;
return this;
}
public Builder<T> width(double width) {
this.width = width;
return this;
}
}
public static Builder<?> builder() {
return new Builder<Rectangle>()
{
@Override
public Rectangle build()
{
return new Rectangle(this);
}
};
}
protected Rectangle(Builder<?> builder) {
super(builder);
this.height = builder.height;
this.width = builder.width;
}
}
...すぐに問題が発生します。あなたはそれをコンパイルするつもりはない
Rectangle r = Rectangle.builder().opacity(0.5).height(50).width(100).build();
ような何かをしようとすると、opacity()
ので、それは、ちょうどShape.Builder<Rectangle>
を返します知りません。だから、少なくとも由来に最も由来から、順番に属性を呼び出す必要があり:
Rectangle r = Rectangle.builder().height(50).width(100).opacity(0.5).build();
あなたはこれを回避したい場合は、スーパークラスのメソッドはまだするように、属性方法が一般的なようにする必要がありサブクラスのビルダーを返します。そこ私の知る限り、これは100%の信頼性を高めるための方法はないのですが、いくつかの自己参照ジェネリックであなたが近づくことができます:
class Shape
{
private final double opacity;
public double getOpacity()
{
return opacity;
}
public static abstract class ShapeBuilder<S extends Shape, B extends ShapeBuilder<S, B>>
{
private double opacity;
@SuppressWarnings("unchecked")
public B opacity (double opacity)
{
this.opacity = opacity;
return (B) this;
}
public abstract S build();
}
private static class DefaultShapeBuilder extends ShapeBuilder<Shape, DefaultShapeBuilder>
{
@Override
public Shape build()
{
return new Shape(this);
}
}
public static ShapeBuilder<?, ?> builder()
{
return new DefaultShapeBuilder();
}
protected Shape (ShapeBuilder<?, ?> builder)
{
this.opacity = builder.opacity;
}
}
class Rectangle extends Shape
{
private final double height;
private final double width;
public double getHeight()
{
return height;
}
public double getWidth()
{
return width;
}
public static abstract class RectangleBuilder<S extends Rectangle, B extends RectangleBuilder<S, B>> extends ShapeBuilder<S, B>
{
private double height;
private double width;
@SuppressWarnings("unchecked")
public B height (double height)
{
this.height = height;
return (B) this;
}
@SuppressWarnings("unchecked")
public B width (double width)
{
this.width = width;
return (B) this;
}
}
public static RectangleBuilder<?, ?> builder()
{
return new DefaultRectangleBuilder();
}
protected Rectangle (RectangleBuilder<?, ?> builder)
{
super(builder);
this.height = builder.height;
this.width = builder.width;
}
private static class DefaultRectangleBuilder extends RectangleBuilder<Rectangle, DefaultRectangleBuilder>
{
@Override
public Rectangle build()
{
return new Rectangle(this);
}
}
}
class RotatedRectangle extends Rectangle
{
private final double theta;
public double getTheta()
{
return theta;
}
public static abstract class RotatedRectangleBuilder<S extends RotatedRectangle, B extends RotatedRectangleBuilder<S, B>> extends Rectangle.RectangleBuilder<S, B>
{
private double theta;
@SuppressWarnings("Unchecked")
public B theta (double theta)
{
this.theta = theta;
return (B) this;
}
}
public static RotatedRectangleBuilder<?, ?> builder()
{
return new DefaultRotatedRectangleBuilder();
}
protected RotatedRectangle (RotatedRectangleBuilder<?, ?> builder)
{
super(builder);
this.theta = builder.theta;
}
private static class DefaultRotatedRectangleBuilder extends RotatedRectangleBuilder<RotatedRectangle, DefaultRotatedRectangleBuilder>
{
@Override
public RotatedRectangle build()
{
return new RotatedRectangle(this);
}
}
}
class BuilderTest
{
public static void main (String[] args)
{
RotatedRectangle rotatedRectangle = RotatedRectangle.builder()
.theta(Math.PI/2)
.width(640)
.height(400)
.height(400)
.opacity(0.5d) // note attribs can be set in any order
.width(111)
.opacity(0.5d)
.width(222)
.height(400)
.width(640)
.width(640)
.build();
System.out.println(rotatedRectangle.getTheta());
System.out.println(rotatedRectangle.getWidth());
System.out.println(rotatedRectangle.getHeight());
System.out.println(rotatedRectangle.getOpacity());
}
}
注@SuppressWarnings
注釈が。サブクラスによってFooBuilder
が常にFooSuperclassBuilder<Foo, FooBuilder>
に拡張されるという規則が破られた場合、システムは故障します。
コードがどのように醜いかを見ることができます。この時点で、Item 2を放棄し、代わりにItem 16: Favor composition over inheritanceを瞑想したほうがよいかもしれません。
IMHOビルダーパターンを使用している場合は、これらすべてのプライベートフィールドを最終的にする必要があります。 –
@AdamGentそれを指摘してくれてありがとう。彼らは本当に私のアプリで最終的です。どういうわけか、ここで質問を投稿している間にそれを逃した。 – curioustechizen