2017-06-13 49 views
3

我想爲抽象類創建抽象構建器(雖然它不需要是抽象的),並且抽象類的每個子類都可以擁有自己的子類Builder。我也希望每個字段/屬性都必須填寫。所以我使用Twist生成器模式(https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/)。使用Java中的捻度子類化構建器模式

我遇到這是解決了這個問題,我剛纔問了一個問題:Generic parent object cannot be returned as child without cast 但我現在無法作出具體的多/子建設者。

最後,我想實例化對象是這樣的:

ConcreteBuilderA.getBuilder().setValue(Object value).setConcreteValue(int num).build() 

其中的setValue()屬於AbstractBuilder和他人的concreteBuilder。

我最好的射門被(大量簡化和抽象):

/** 
* @param<B> the type of builded object it should return. 
* @param<S> the type of the builder subclass. 
* @param<L> the type of the linking interface. 
*/ 
public abstract class AbstractBuilder<B extends AbstractClass, S extends AbstractBuilder, L> implements ValueSetter<L> 
{ 
    protected B buildable; 
    @Override 
    public L setValue(Object value) 
    { 
     //set the value 
     return this;//<-- returns Object, blocking the use of the ConcreteBuilder methods 
    } 
    public abstract B build(); 
} 

|

public class ConcreteBuilder extends AbstractBuilder<ConcreteProduct, ConcreteBuilder, ConcreteValueSetter> implements ConcreteValueSetter 
{ 
    @Override 
    public ConcreteBuilder setConcreteValue(int num) 
    { 
     //set value 
     return this; 
    } 
    @Override 
    public ConcreteProduct build(); 
    { 
     return buildable; 
    } 
} 

|

public interface ValueSetter<L> 
{ 
    public L setValue(Object value); 
} 

|

public interface ConcreteValueSetter 
{ 
    public ConcreteBuilder setConcreteValue(int num); 
} 

正如所標記的,當'切換'到子類構建方法時,這會停止鏈。 我已經做了一些變種,我不能得到它的工作。

所以我真的想知道這是否可能。如果是這樣,我想看看如何。如果不是,我想知道一些符合我要求的技術。

在此先感謝!

+1

嗨!試試這個:'public abstract class AbstractBuilder >實現ValueSetter ',並在'setValue'中將'this'轉換爲'L'。無論如何,我覺得這太複雜了。你確定這是值得的嗎?我喜歡Bloch的方法來在構建器構造函數中要求必需的字段,而不是具有setter接口。使用setter接口,您最終會圍繞泛型類型參數旋轉... –

+1

我認爲在'ConcreteBuilder'中,您意外地切換了第一個和第二個泛型類型參數。它應該是'公共類ConcreteBuilder擴展AbstractBuilder ',它不應該是?順便說一句,什麼是'LinkingInterface'?也請顯示它的代碼。 –

+0

我想使用Builders構造函數,但在真實項目中,抽象對象已經擁有超過4個屬性,這些屬性都是強制性的......而具體的wel ...更多。將所有這些參數放在一起會違反SIG可維護代碼規則,即每個單元的參數不應超過4個。 – RabbitBones22

回答

1

我在Federico Peralta Schaffner的幫助下發現了答案。 我很可能讓我的真實項目中的建築師變得複雜。 所以這裏是代碼一個Builder上帶有一個捻+繼承:

/** 
* 
* @param <P> the type of the product. 
* @param <L> the linking interface. 
*/ 
public class AbstractBuilder<P extends AbstractClass, L> implements ValueSetterOne<L>, ValueSetterTwo<L>{ 

    protected P toBeBuild; 
    @Override 
    public L setValueTwo(int value) { 
     //set value 
     return (L) this; 
    } 
    @Override 
    public ValueSetterTwo<L> setValueOne(int value){ 
     //set value 
     return this; 
} 

|

public class ConcreteBuilder extends AbstractBuilder<ConcreteClass, NameSetter> implements NameSetter, Optional{ 
    public static ValueSetter<NameSetter> getBuilder() 
    { 
     AbstractBuilder<ConcreteClass, NameSetter> builder = new ConcreteBuilder(); 
     builder.toBeBuild = new ConcreteClass(); 
     return builder; 
    } 

    @Override 
    public Optional buildName(String name) { 
     this.toBeBuild.setCharacterName(name); 
     return this; 
    } 

    @Override 
    public ConcreteClass build() { 
     return this.toBeBuild; 
    } 

    @Override 
    public Optional addExtraObject(Object extra) { 
     System.out.println("test"); 
     return this; 
    } 
} 

|

public interface ValueSetterOne<L> { 
    public ValueSetterTwo<L> setValueOne(int value); 
} 

|

public interface ValueSetterTwo<L> { 
    public L setValue(int value); 
} 

|

public interface NameSetter { 
    public Optional buildName(String name); 
} 

|

public interface Optional { 
    public ConcreteClass build(); 
    public Optional addExtraObject(Object extra); 
} 

然後對其進行測試: ConcreteBuilder.getBuilder().setValueOne(0).setValueTwo(1).buildName("tricky").addExtraObject(args).build();

1

你的問題是懶惰的編程技術的症狀。 嘗試一下;假裝你是一名專業軟件開發人員:

ConcreteBuilderA builder = ConcreteBuilderA.getBuilder(); 
ThingBeingBuilt thing; 

builder.setValue(value); 
builder.setConcreteValue(num); 
thing = builder.build() 
+0

我不確定你想表達什麼。你的意思是我不應該把制約因素(強制性領域)放在建設者身上,而只是使用它? – RabbitBones22

+0

無需從setXxxx方法返回構建器。如果你不依賴於這個(壞)技術,那麼setValue和setConcreteValue方法的實現位置並不重要。我的觀點是:鏈接調用是一個懶惰的開發人員青睞的懶惰技術。放棄這種技術,你的設計就很好。 – DwB

+0

好吧......但爲什麼它'壞'呢?我想我誤解了建造者模式。它意味着用於構建同一個權利的多個對象?而不是實際構建複雜的對象? – RabbitBones22