通过儿童建设者

时间:2014-09-23 21:59:23

标签: java oop polymorphism

我有一个案例,我有类似的东西:

public abstract class Base{    
   private Base sibling;

   public Base( Base sibling ){
         this.sibling = sibling;
   }

   public Base getSibling(){
       return this.sibling;
   }
}

public class ChildA extends Base{
      private ChildB brother;

      public ChildA(){
          this.brother = new ChildB( this );
      }

      public ChildB getBrother(){ return this.brother }
      public void methodA(){ ... }
      public void methodB(){ ... }

}

public class ChildB extends Base{
   public childB someMethodX(){ ... }
   public childB someMethodY(){ ... }
}

现在我需要它,以便在做类似的事情时:

   var child = new ChildA()
       .getBrother()
           .someMethodX()
           .someMethodY()
           .getSibling()
       .methodA()
       .methodB()

.getSibling()让我回到ChildA的范围内。目前,它似乎正在返回Base的一个实例,并在methodA()课程中向我提供Base不存在的错误。

我已经看过GenericTypes的一些案例,因为在这种情况下可能是我想要的,但我还是很难实现它。任何示例/指针/链接都将非常感激。

感谢。

2 个答案:

答案 0 :(得分:1)

除非通过施法,否则你无法做到你想做的事情:

  var child = new ChildA()
       .getBrother() // ChildB 
           .someMethodX() // void
           .someMethodY() // compile error
           .getSibling()  // compile error (someMethodY = void), Base
       .methodA() // compile error, methodA does not exists on Base
       .methodB() // idem.

我建议你采用两种方法:

  • Base上的通用类型,以便Base可以返回this作为子类型而不是Base。如果ChildA扩展Base,使用两种方法ChildA::setFoobarBase::setSaxon,则可以执行:builder.setSaxon("A").setFoobar("B"),因为通用。{/ p>

    public class Base<B extends Base<B>> {
      protected abstract B self();
      public <C extends Base<C>> B setSibling(Base<C> base) {
        this.sibling = base;
        return self(); // or (B)this
      }
    }    
    public class ChildA extends Base<ChildA> {
      protected ChildA self() {return this;}
    }
    public class ChildB extends Base<ChildB> {}
    

    这样可行:

    ChildA a = new ChildA().setSibling(new ChildB().setSibling(new ChildA()));
    

    self方法将避免在每个(B)this方法中转换为setXXX

  • 使用B的构建器包装器:返回一个中间对象ChildBBuilder,其中&#34; final&#34;方法getSibling()ChildB的新实例与其所属的ChildA相关联,并返回该对象以继续链:

    public class ChildA extends Base{
      private ChildB brother;
      public ChildBBuilder getBrother() {
        return new ChildBBuilder() {
          public ChildA getSibling() {
            ChildA.this.brother = create();
            return ChildA.this;
          }
        };
      }
    }
    
    public class ChildBBuilder {
      public ChildBBuilder(ChildA parent) {
        this.parent = parent;
      }
      ... setter ...
    
      public ChildB create() {
        return new ChildB();
      }
    
      public ChildA getSibling() {
        throw new UnsupportedOperationException();
      }
    }
    

    ChildBBuilder是一个独立的构建器,允许一些getSibling操作,其默认实现失败。我们创建一个匿名抽象类来处理这种情况。

我已经在我的一些项目中使用了第一个案例,使用了&#34; base builder&#34;。

对于第二种情况,我从未使用过它。如果你正在尝试为你的一些工作创建一个DSL,不要忘记,即使它很好也可能是它的价值太多了。

如果您正在使用Java 8,则可以将模式扩展为纯抽象实现:see my answer here

答案 1 :(得分:1)

这不起作用,因为在methodA中定义了ChildA,但getSibling返回Base引用。虽然此Base引用恰好指向ChildA对象,但您应该执行显式转换或概括Base类型。

在这种特殊情况下,您可以简单地覆盖getSibling

class ChildB extends Base {
  public ChildB(ChildA sibling) {
    super(sibling);
  }

  @Override
  public ChildA getSibling() {
    return (ChildA) super.getSibling();
  }
}

如果有很多像ChildB这样的课程,那么这不会很好地扩展。此外,ChildB被限制为仅包含ChildA兄弟姐妹。


编辑:

  

它可能并不总是childB

好吧,假设您不需要Base类是通用的,您可以将其替换为:

class ChildB <T extends Base> extends Base {
    public ChildB(T sibling) {
      super(sibling);
    }


    @Override
    @SuppressWarnings("unchecked")
    public T getSibling() {
      return (T) super.getSibling();
    }
}

您可以按如下方式对其进行实例化:

brother = new ChildB<ChildA>(this);