1. 程式人生 > >遇到多個構造器引數時要考慮用構建器Bulider

遇到多個構造器引數時要考慮用構建器Bulider

靜態工廠和構造器有個共同的侷限性:他們都不能很好的擴充套件大量的可選引數,
比如包裝食品營養成分標籤,含量,卡路里,等等,有可能會超過20個可選域,對於這樣的類,應該用那種構造器或靜態方法來寫呢,

構造器:
程式設計師一般習慣採用過載構造器來實現,第一個構造器,提供一個必要引數,第二個構造器提供,一個必要引數,一個可選引數,依次類推.

public NutritionFacts(int servingSize){}
public NutritionFacts(int servingSize,int calories){}
public NutritionFacts(int
servingSize,int calories,int fat){}

缺點
構造器呼叫通常需要許多本不想設定引數,但是不得不為他們傳遞值.隨著引數數目的增加,就很快失去了控制

javabean模式:
這種模式下呼叫一個午餐構造器來建立物件,然後呼叫setter方法來設定每個必要的引數,以及每個可選引數.

public class NutritionFacts{
private int servingSize=-1;
private int servings=-1;
private int calories=0;
...getter setter省略
}

優點:彌補了重疊構造器模式的不足,建立例項很容易,程式碼易讀性強

NutritionFacts cocaCola=new NutritionFacts();
cocaCola.setServingSize(22);
cocaCola.setServings(22);
...

缺點:
其構造過程中被分到幾個呼叫中,在構造過程中JavaBean可能處於不一致的狀態,這種失敗與包含錯誤程式碼,類無法僅僅通過檢驗構造器引數的有效性來保證一致性,試圖使用不一致狀態的物件,將會導致失敗,這種失敗與包含錯誤的程式碼大相徑庭,因此它除錯起來非常困難,另一點不足,JavaBean阻止了把類做成不可變類的可能,這就需要額外的努力來確保他的執行緒安全.

構建器模式:

public class NutritionFacts {

    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Bulider{
        private  int servingSize;
        private  int servings;
        private  int calories=0;
        private  int fat=0;
        private  int sodium=0;
        private  int carbohydrate=0;

        public Bulider( int servingSize,int servings) {
            this.servings=servings;
            this.servingSize=servingSize;
        }
        public Bulider calories( int var) {
            this.calories=var;
            return this;
        }
        public Bulider fat( int var) {
            this.fat=var;
            return this;
        }
        public Bulider sodium( int var) {
            this.sodium=var;
            return this;
        }
        public Bulider carbohydrate( int var) {
            this.carbohydrate=var;
            return this;
        }

        public NutritionFacts bulid() {
            return new NutritionFacts(this);
        }
    }
    private NutritionFacts(Bulider bulider) {
        servings=bulider.servings;
        servingSize=bulider.servingSize;
        calories=bulider.calories;
        fat=bulider.calories;
        sodium=bulider.sodium;
        carbohydrate=bulider.carbohydrate;
    }


}
//客戶端測試
@Test
public void codeTest() {
    NutritionFacts nutritionFacts=new NutritionFacts.Bulider(240, 8).
    calories(100).sodium(33).carbohydrate(22).bulid();
}

優勢:
bulider可以有多個可變引數,構造器就像方法一樣,只能有一可變引數,因為builder利用單獨的方法來設定每個引數,想要多少個就key有多少個, 該模式十分靈活,可以利用單個bulider物件,引數可以在建立物件時調整,也可以根據不同物件改變,buliderkey自動填充某些域,例如每次建立物件時自動增加序列號
不足:
為了建立物件,必須先建立它的構建器,雖然建立構建器的開銷在實踐中可能不那麼明顯,但是在某些注重效能的情況下,可能就成問題,Bulider模式比重疊構造器模式更加冗長因此只有很多引數的時候才使用.