2016-08-18 55 views
9

假設我需要一些DerivedBuilder來擴展一些BaseBuilder。基本構建器有一些方法,如foo(它返回BaseBuilder)。派生建築師有方法bar。應在方法foo後調用方法bar。爲了做到這一點,我可以在DerivedBuilder像這樣覆蓋foo方法:Java通用構建器

@Override 
public DerivedBuilder foo() { 
    super.foo(); 
    return this; 
} 

的問題是,BaseBuilder有很多像foo方法,我必須重寫他們中的每一個。我不想這樣做,所以我嘗試使用泛型:

public class BaseBuilder<T extends BaseBuilder> { 
    ... 

    public T foo() { 
     ... 
     return (T)this; 
    } 
} 

public class DerivedBuilder<T extends DerivedBuilder> extends BaseBuilder<T> { 
    public T bar() { 
     ... 
     return (T)this; 
    } 
} 

但問題是,我仍然不能寫

new DerivedBuilder<DerivedBuilder>() 
     .foo() 
     .bar() 

即使T這裏是DerivedBuilder。我可以做什麼以避免覆蓋很多功能?

+1

有了這個計算策略仿製藥,你可以撥打:'新DerivedBuilder ()。 FOO()。欄()'。它將首先工作並執行'foo',然後執行'bar'。如果你想調用更多的'BaseBuilder'方法,最後你想調用'DerivedBuilder'方法,那麼這是不可能的,因爲第二次,方法返回'BaseBuilder'的引用,你不能調用'DerivedBuilder' s方法。 –

+0

@ Sandeep.KI試圖執行該操作,編譯器抱怨''Bar'沒有在'BaseBuilder'中定義,因爲那時我執行'.foo().bar()'編譯器在執行'foo之後唯一知道'T'的東西'是這個'T'擴展了'BaseBuilder' – PepeHands

+0

請參見[this](http://stackoverflow.com/questions/4217013/how-to-force-derived-class-to-call-super-method-like-android -does)和[this](http://stackoverflow.com/questions/6853638/require-override-of-method-to-call-super)和[this](http://stackoverflow.com/questions/6142460/how-do-i-force-a-polymorphic-call-to-the-super-method)... – user1803551

回答

5

你的問題是DerivedBuilder定義:

class DerivedBuilder<T extends DerivedBuilder>; 

然後用擦除參數new DerivedBuilder<DerivedBuilder<...what?...>>()類型實例化它。

你需要完全定義的派生類型,像這樣:

public class BaseBuilder<T extends BaseBuilder<T>> { 
    @SuppressWarnings("unchecked") 
    public T foo() { 
     return (T)this; 
    } 
} 

public class DerivedBuilder extends BaseBuilder<DerivedBuilder> { 
    public DerivedBuilder bar() { 
     return this; 
    } 
} 

檢查ideone.com

+0

是否還有可能進一步派生'DerivedBuilder',例如'SubDerivedBuilder'? 'SubDerivedBuilderM <...> extends DerivedBuilder <...>' –

+1

@MCEmperor是的,但是你需要讓所有派生類型都通過完整的類型到它們的基類。檢查[this fork](http://ideone.com/ZIAuqs) – BeyelerStudios

0

我的理解是你的問題是foo()方法應該在方法bar()之前執行。
如果這是正確的,您可以應用模板設計模式。
在BaseBuilder中創建一個抽象方法欄。
而一種新的方法說'模板'。方法模板將定義序列 - 首先執行foo(),然後執行bar()。
DerivedBuilder將提供方法欄的實現。

public abstract class BaseBuilder { 

    public void foo(){ 
     System.out.println("foo"); 
    } 

    public abstract void bar(); 

    public void template(){ 
     foo(); 
     bar(); 
    } 
} 

public class DerivedBuilder extends BaseBuilder{ 

    @Override 
    public void bar() { 
     System.out.println("bar");  
    } 

    public static void main(String[] args) { 
     BaseBuilder builder = new DerivedBuilder(); 
     builder.template(); 
    } 
} 


希望這有助於。

2

取代鑄造return (T) this;我在這裏做了Class.cast(this)

認識到:

BaseBuilder.build(ExtendedBuilder.class).foo().bar().foo().bar(); 

在教主每個類都需要知道實際的最終子類,所以我選擇了做一個工廠方法build基類。

this到實際的孩子的演員在基類的最後一個方法也完成,提供return me();

class BaseBuilder<B extends BaseBuilder<B>> { 

    protected Class<B> type; 

    public static <T extends BaseBuilder<T>> T build(Class<T> type) { 
     try { 
      T b = type.newInstance(); 
      b.type = type; 
      return b; 
     } catch (InstantiationException | IllegalAccessException e) { 
      throw new IllegalStateException(e); 
     } 
    } 

    protected final B me() { 
     return type.cast(this); 
    } 

    B foo() { 
     System.out.println("foo"); 
     return me(); 
    } 
} 

class ExtendedBuilder extends BaseBuilder<ExtendedBuilder> { 

    ExtendedBuilder bar() { 
     System.out.println("bar"); 
     return me(); 
    } 
} 
+0

現在你有一個Builder工廠。此外,'type'字段和'type.cast(this)'是沒有意義的,因爲它不提供任何額外的編譯時安全性並且使整個事情複雜化。 – Clashsoft

+0

@XetraSu建議'靜態類'這可能適合他們的用法。 –

4

除了BeyelerStudios's answer,如果你想進一步嵌套,你可以這樣做:

class Base<T extends Base<?>> { 
    public T alpha() { return (T) this; } 
    public T bravo() { return (T) this; } 
    public T foxtrot() { return (T) this; } 
} 

class Derived<T extends Derived<?>> extends Base<T> { 
    public T charlie() { return (T) this; } 
    public T golf() { return (T) this; } 
} 

class FurtherDerived<T extends FurtherDerived<?>> extends Derived<T> { 
    public T delta() { return (T) this; } 
    public T hotel() { return (T) this; } 
} 

class MuchFurtherDerived<T extends MuchFurtherDerived<?>> extends FurtherDerived<T> { 
    public T echo() { return (T) this; } 
} 

public static void main(String[] args) { 
    new MuchFurtherDerived<MuchFurtherDerived<?>>() 
     .alpha().bravo().charlie().delta().echo().foxtrot().golf().hotel() 
     .bravo().golf().delta().delta().delta().hotel().alpha().echo() 
     .echo().alpha().hotel().foxtrot(); 
}