2014-09-23 73 views
0

我有,我有類似的情況:傳遞兒童建設者

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的一些情況,可能正是我想在這種情況下,但我一直在努力實現它。任何示例/指針/鏈接將不勝感激。

謝謝。

+0

您是否嘗試投射到ChildA? – lifus 2014-09-23 22:03:04

回答

1

這不起作用,因爲methodAChildA中定義,但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); 
+0

對於我的情況,這個解決方案的問題是ChildB可能包含在Base的其他子類中,所以getSibling應該返回它們。即,它可能並不總是孩子B – SS44 2014-09-24 14:54:00

+0

好的,第二種選擇呢? – lifus 2014-09-24 15:12:46

+0

感謝您的幫助,解決方案已被接受。 – SS44 2014-09-24 15:27:42

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::setFoobar,Base::setSaxon,則由於泛型原因,將執行:builder.setSaxon("A").setFoobar("B")

    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方法將避免在每個setXXX方法強制轉換爲(B)this。使用

  • 對於B的助洗劑包裝:返回一箇中間對象ChildBBuilder,其「最終」方法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操作,其默認實現將失敗。我們創建一個匿名的抽象類來處理這種情況。

我已經在我的一些項目中使用了第一個案例,「基礎構建器」。

對於第二種情況,我從來沒有使用它。如果你正在努力爲你的一些工作創建一個DSL,不要忘記,即使它很好,所有東西都值得它值得。

如果您正在使用Java 8,則可以將該模式擴展爲純粹的抽象實現:see my answer here