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

Den*_*ich 2 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) {...}
}
Run Code Online (Sandbox Code Playgroud)

我想为每个形状使用构建器模式.所以我为每一个添加了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(/*...*/) {/*...*/}
}
Run Code Online (Sandbox Code Playgroud)

编辑: 这里使用Generic是为了允许以任何顺序使用Builder方法.例如,为了允许以下调用:

new Circle.Builder()
    .setLocation(0, 0)
    .setRadius(10)
    .build();
Run Code Online (Sandbox Code Playgroud)

我的问题在于这个演员:

public T setLocation(double x, double y) {
    // ...
    return (T)this; // ? - is there a way to avoid this casting?
}
Run Code Online (Sandbox Code Playgroud)

我正在努力寻找避免这种演员的方法.我到目前为止找到的唯一方法是在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();
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

因此,每个派生的构建器都必须实现它:

@Override
protected Circle getBuilder() { 
    return this; 
}
Run Code Online (Sandbox Code Playgroud)

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

问题:有没有更优雅的方法来避免铸造?

Hol*_*ger 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(/*...*/) {/*...*/}
}
Run Code Online (Sandbox Code Playgroud)