2017-07-31 68 views
2

我敢肯定,這個問題可能已經回答,但環顧四周後,我不確定正確的術語讓我一個堅實的答案。無論是這個,還是我沒有完全理解的東西。JAVA返回父對象 - 從繼承的繼承 - 生成器模式

我試圖創建具有不同方法的構建器的選擇,但是,它們都必須從「基礎」構建器繼承。這很好,但我無法讓它返回正確的對象來繼續構建器模式。

什麼,我已經試過一個例子:

public class Builder1 { 
    protected String string = new String(); 

    public <T extends Builder1 > T append1(String string) { 
     this.string += string; 
     return (T)this; 
    } 

    public void print() { 
     System.out.println(this.string); 
    } 

} 


public class Builder2 extends Builder1 { 

    public <T extends builder2 > T append2(String string) { 
     this.string += string; 
     return (T)this; 
    } 

} 


public class Builder3 extends Builder2 { 

    public <T extends Builder3 > T append3(String string) { 
     this.string += string; 
     return (T)this; 
    } 

} 

所以,如果我這樣做:

new Builder3().append3("")... 

我可以訪問Builder3,Builder2和Builder1中的所有方法 - 很好。
的問題,當我訪問的Builder1或Builder2的方法之一,像這樣出現:現在

new Builder3().append1("")... 

,我只能訪問Builder1的方法,我不能去Builder2或Builder3。

正如我所說,我相信這已經在其他地方得到了回答,所以請隨時指點我任何有關它的帖子。
任何幫助,將不勝感激,謝謝。

編輯:
我還要指出的是,這些方法都將做不同的事情。我的例子看起來好像他們在不同的地方做同樣的事情。

+0

首先,您應該遵循Java命名約定。班級名稱**總是**以大寫字母開頭! –

+0

是的,對不起,我通常這樣做,但這只是一個例子,但我會進行編輯。 :P – user3208218

回答

0

哈哈!我剛剛經歷了這個。多麼痛苦。這對我有用。它位於基類中。但是,我將T傳回給基類。您可以通過覆蓋每個子類中的方法來獲得相同的效果,每個類都返回它自己的類型。

/** 
* Return this as type T. This is used by fluent setters and build. 
* 
* @return 
*/ 
@SuppressWarnings("unchecked") 
protected T fetchThisAsT() { 
    return (T) this; 
} 
2

[聲明:未測試的代碼] 我要這麼做定義的基append*方法的抽象基類。農行看起來像......

public abstract class BaseBuilder { 

    protected String string = ""; 

    public void print() { 
     System.out.println(this.string); 
    } 

    abstract <T extends BaseBuilder> T append1(String string); 

    abstract <T extends BaseBuilder> T append2(String string); 

    abstract <T extends BaseBuilder> T append3(String string); 

} 

然後,比如說,爲Builder1,你可以實現append1(..),並引發了其他異常。

public class Builder1 extends BaseBuilder { 
    public <T extends Builder1> T append1(String string) { 
     this.string += string; 
     return (T)this; 
    } 

    public <T extends Builder1> T append2(String string) { 
     throw new UnsupportedOperationException("something"); 
    } 

    public <T extends Builder1> T append3(String string) { 
     throw new UnsupportedOperationException("something"); 
    } 
} 

同樣的原則Builder2Builder3

+0

我理解這種方法,但它正在做一些我想要避免的事情。我希望它繼承整個方法的原因是因爲基類中有很多它們,我不想每次都寫出它們。在使用每個構建器(The Java Assist/Intellisense thing)時,我也不想看到IDE中不支持的方法。感謝您的意見,但。 – user3208218

1

要開始了,你應該使用StringBuilder爲附加的文字,而不是String string = new String()

string += string會創建一個新的StringBuilder,這意味着每次調用Builder#append方法時都會創建一個。

class Builder1 { 
    private StringBuilder builder = new StringBuilder(); 

    public Builder1 append1(String text) { 
     builder.append(text); 
     return this; 
    } 

    public String build() { 
     return builder.toString(); 
    } 
} 

接下來,你應該知道BaseBuilder接口應該只公開的是所有建設者們的行爲。您不應將此接口定義爲append2append3。它應該只包含build

interface Builder<T> { 
    T build(); 
} 

最後,對於解決方案,您應該decorating添加的功能。

你將不得不Builder1

class Builder1 implements Builder<String> { 
    private StringBuilder builder = new StringBuilder(); 

    public Builder1 append1(String text) { 
     builder.append(text); 
     return this; 
    } 

    @Override 
    public String build() { 
     return string.toString(); 
    } 
} 

Builder1本身表達你如何繼續爲其他建設者裝飾:

  • Builder1是由它自己的建設者。
  • 調用委託給該構建器,但返回當前實例。

Builder2將組合成Builder1的:

class Builder2 implements Builder<String> { 
    private Builder1 builder = new Builder1(); 

    public Builder2 append(String text) { 
     builder.append(text); 
     return this; 
    } 

    public Builder2 append2(String text) { 
     //custom behavior 
     return this; 
    } 

    public String build() { 
     return builder1.build(); 
    } 
} 

Builder3將組成Builder2

class Builder3 implements Builder<String> { 
    private Builder2 builder = new Builder2(); 

    public Builder3 append1(String text) { 
     builder.append1(text); 
     return this; 
    } 

    public Builder3 append2(String text) { 
     builder.append2(text); 
     return this; 
    } 

    // custom append3 

    // build() returns builder.build() 
} 

接口,用於交互存在:Builder定義所有製造商如何互動用。如果你不想Builder1append3,那麼基本接口不應該定義它。

0

按照Type Erasure定義

替換泛型類型所有類型參數與他們的界限或對象,如果類型參數是無限的。

所以,append1()後,返回類型實際上是Builder1。爲了在append1之後append2append3,您可以在所有3個類別中將<T extends Builder*>更改爲<T extends Builder3>