2017-08-28 247 views
3

我想實現一個生成器模式與靜態內部類可以說與域的類A(A1,A2,A3),B與場(B1,B2)和C字段(C1),而所有股票領域(S1,S2)從超類父類:的Java Builder模式與繼承

public class A extends SuperClass { 
    private final String a1; 
    ... 

    private A(ABuilder builder) { 
     super(builder); 
     this.a1 = builder.a1; 
     ... 
    } 

    public static class ABuilder extends SuperClassBuilder implements ABuilderInterface { 
     private String a1; 
     ... 

     @Override 
     public ABuilder withA1(String a1) { 
      this.a1 = a1; 
      return this; 
     } 
     ... 

     @Override 
     public SuperClass build() { 
      return new A(this); 
     } 
    } 
} 

因此對B和C的建設者只是不同,他們有自己的領域和實現自己的接口(BBuilderInterface和CBuilderInterface),而這些接口僅限定要實施哪些方法:

public interface ABuilderInterface extends SuperClassBuilderInterface { 
    ABuilderInterface withA1(String a1); 
    ... 
} 
...<interfaces for B and C> 

public interface SuperClassBuilderInterface { 
    SuperClassBuilderInterface withS1(String s1); 
    ... 
    SuperClass build(); 
} 

// Usage of the builders: 
public SuperClass foo() { 
    return new A.ABuilder() 
     .withA1(...) // returns ABuilderInterface 
     ... 
     .withS1(...) // returns SuperClassBuilderInterface 
     ... 
     .build(); 
} 

public abstract class SuperClass { 
private final String s1; 
... 

protected SuperClass(SuperClassBuilder builder) { 
    this.s1 = builder.s1; 
    ... 
} 

protected static abstract class SuperClassBuilder implements SuperClassBuilderInterface { 
    private String s1; 
    ... 

    @Override 
    public SuperClassBuilder withS1(String s1) { 
     this.s1 = s1; 
     return this; 
    } 
    ... 

    @Override 
    public abstract SuperClass build(); 
} 
} 

現在你可以發現當我使用構建器的時候,我必須首先注意與子類​​相關的方法,然後鏈接超類的方法,這不是什麼大問題,但仍不確定是否良好的做法。 另一方面,我可以將兒童類的...方法一起添加到超類接口中,然後限制消失,但是接下來我有一個與不同子類的方法混合的接口。

哪一個你更喜歡/建議?

+0

是什麼在''ABuilder' withS1()'回報? – alayor

+0

ABuilder @alayor中沒有withS1(),因爲它使用的是父類。這個想法是,A,B,C構建器只包含它們特定的...方法,而共享的構件保留在超級構建器中。 – radio

+2

這是一個非常常見的問題。一種模式是在超類上定義一個通用的「自我類型」,並通過其方法返回。 – shmosel

回答

5

修改父類的構造器使用的F-界(又名奇異遞歸模板模式)。

public interface SuperClassBuilderInterface<SELF extends SuperClassBuilderInterface<SELF>> { 
    SELF withS1(String s1); 
    // etc. 
    Superclass build(); 
} 

然後,你必須:

class SuperClassBuilder<SELF extends SuperClassBuilder<SELF>> implements SuperClassBuilderInterface<SELF> 

interface ABuilderInterface<SELF extends ABuilderInterface<SELF>> extends SuperClassBuilderInterface<SELF> 

class ABuilder extends SuperClassBuilder<ABuilder> implements ABuilderInterface<ABuilder> 

注意的SuperClassBuilder實現必須包含形式return (SELF)this;的選中轉換。這個類型系統在理論上足夠強大以至於不需要這個,但是最終的編碼可能會非常難看(參見this),它可能不值得。

編輯:這是什麼意思@shmosel

+0

我只是試了一下,它的工作,非常感謝。首先,我不喜歡它,因爲它增加了很多泛型,我不明白它們是如何工作的乍一看,需要三思而行。但對於調用者來說,它更容易,因爲他不會有任何限制 – radio

+0

btw。這是正確的?: 'SuperClassBuilder'的實現返回自身作爲'回報(SELF)這一點;'你提到和 'ABuilderInterface'的方法返回SELF及其實現返回ABuilder – radio

+0

是。不過,我會實際編輯答案,不要使用未經檢查的轉換。 – HTNW