Java builder 模式——抽象 builder

标签 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) {...}
}

我想为每个形状使用构建器模式。所以我为他们每个人都添加了构建器:

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; 
}

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

问题:有没有更优雅的方法来避免强制转换?

最佳答案

你无法避免为每个子类添加一些额外的代码,但你可以避免未经检查的强制转换。只需创建一个 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(/*...*/) {/*...*/}
}

关于Java builder 模式——抽象 builder ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27530750/

相关文章:

java - 有没有办法覆盖 JPA 中实体子类中的 ID?

java - 安全的多态性实践?

java - 这段代码有什么问题,数字溢出警告

java - NullPointerException 未引用任何对象

java - 两个对象的双向依赖

oop - 如何正确创建具有循环依赖性的两个实体?

java - 如何在没有此 ClassNotFoundException 的情况下连接到 Java 中的本地 SQLite?

java - 从Java中的谷歌地图API解析Json数组

java - 在java中创建文件(及其目录)后无法写入文件

java - Java 中的多态参数和字段