Java建造者样式 - 抽象建造者

时间:2014-12-17 16:56:33

标签: java oop polymorphism builder-pattern

首先,我对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; 
}

在我看来有点矫枉过正,但我​​不想得到编辑警告。

问题:有没有更优雅的方法来避免投射?

1 个答案:

答案 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(/*...*/) {/*...*/}
}