2

首先,我对 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(/*...*/) {/*...*/}
}

编辑: 这里使用泛型是为了允许以任何顺序使用 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; 
}

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

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

4

1 回答 1

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(/*...*/) {/*...*/}
}
于 2014-12-17T17:26:18.783 回答