Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java builder模式-抽象生成器_Java_Oop_Polymorphism_Builder Pattern - Fatal编程技术网

Java builder模式-抽象生成器

Java builder模式-抽象生成器,java,oop,polymorphism,builder-pattern,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(

首先,我对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(/*...*/) {/*...*/}
}
我的问题在于这个角色:

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

    //...
}
在我看来,这似乎有些过分,但我不想收到编译警告


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

您不能避免每个子类都有一点额外的代码,但可以避免未经检查的强制转换。只需创建一个
摘要
方法,负责返回正确键入的
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(/*...*/) {/*...*/}
}
类形状{
受保护的静态摘要
类构建基{
/**所有子类都应该实现{@code self()},因为{@code返回this;}*/
抽象T self();
公共T设置位置(双x,双y){
// ...
返回自我();
}
公共T设置FooBar(FooBar x){
// ...
return self();//方法越多,self()就变得越有用
}
公共摘要S build();
}
受保护形状(/*…*/){/*…*/}
}
类圆形延伸形状{
公共静态类生成器扩展了BuilderBase{
@重写最终生成器self(){返回此;}
公共建筑商设置半径(双半径){
//...
归还这个;
}
@凌驾
公共圈构建(){返回新圈(/*…*/);}
}
私人圈子(/*…*/){/*…*/}
}
类矩形扩展形状{
公共静态类生成器扩展了BuilderBase{
@重写最终生成器self(){返回此;}
公共建筑商设置半径(双半径){
//...
归还这个;
}
@凌驾
公共矩形生成(){
返回新矩形(/*…*/);
}
}
公共矩形(/*…*/){/*…*/}
}

@Arkadiy:未经检查的强制转换与一些琐碎、易于证明正确的方法。有些开发人员更喜欢更多但更容易维护的代码,而不是更少但更难维护的代码。从性能的角度来看,这种差异是无关紧要的。我必须承认@Holger的方法更安全,因为它可以处理
类螺旋EdupBuilder扩展BuilderBase
这样的情况,使用ScrewedUpBuilder会在编译时发现这个问题:你想链接一个ScrewedUpBuilder方法,编译器告诉你它在CircleBuilder中不存在。@Holger,实际上,你的解决方案和问题本身中出现的是一样的。就在问题中,它被称为
getBuilder()
,而不是
self()
。尽管如此,我必须说name
self()
在这里更合适。我只是想知道是否有更简单的方法this@Denis伊茨科维奇:当我写我的答案时,我没有注意到你在问题中的答案。答案是Java泛型无法声明
this
类型与类型参数之间的关系。即使是核心类也会遇到这种情况,例如,
Comparable
——如果有一种方法可以声明
T
应该是实现
Comparable
的实际类型,也就是说,它与自身是可比的,那么它就是用这种方法声明的…
@Override
protected Circle getBuilder() { 
    return 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(/*...*/) {/*...*/}
}