設計模式8——Builder設計模式

Builder建造者模式將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。Builder模式是一步一步建立一個複雜的對象,它容許用戶能夠只經過指定複雜對象的類型和內容就能夠構建它們,用戶不須要了解所構建對象的內部具體構建細節,Builder建造設計模式的目的是爲了將構造複雜對象的過程和它的部件解耦。 java

Builder建造者設計模式中有兩個重要角色:Director指導者和Builder建造者。Director指導者至關於設計師或架構師,擁有整個產品各個部件之間關係的構建藍圖。Builder建造者是部件的具體建立者,Builder建造者根據Director指導者的指示建立產品的各個部件,最終由Director構建出完整產品。Builder建造者設計模式的UML圖以下: 設計模式

《Effective java》中有一個關於建造者模式的例子以下: 安全

用一個類表示包裝食品外面顯示的養分成分,其中每份含量和每罐含量是必須的,卡洛里,脂肪,納和碳水化合物是可選參數。
你們通常習慣使用重載構造方法來解決該問題,代碼以下: 架構

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 NutritionFacts(int servingSize, int servings){
		this(servingSize, servings, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories){
		this(servingSize, servings, calories, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories,
						  int fat){
		this(servingSize, servings, calories, fat, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories,
						  int fat, int sodium){
		this(servingSize, servings, calories, fat, sodium, 0);
	}

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

若是想要建立實例對象的時候,就利用參數列表最短的構造方法: app

NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
若是可選參數不少的時候就難以控制,客戶端代碼變得很難編寫,且難以閱讀,若是不當心參數順序混淆了,在編譯的時候很難發現問題,在運行時出錯時難以調試。


第二種你們都會想到的辦法是使用setter方法設置每一個須要的參數,代碼以下:
public class NutritionFacts{
	//必須參數
	private int servingSize = -1;
	private int servings = -1;
	//可選參數
	private int calories = 0;
	private int fat = 0;
	private int sodium = 0;
	private int carbohydrate = 0;
	public NutritionFacts(){}
	public void setServingSize(int val){
		this.servingSize = val;
	}
	public void setServings(int val){
		this.servings = val;
	}
	public void setCalories(int val){
		this.calories = val;
	}
	public void setFat(int val){
		this.fat = val;
	}
	public void setSodium(int val){
		this.sodium = val;
	}
	public void setCarbohydrate(int val){
		this.carbohydrate = val;
	}
}
使用setter方法能夠彌補重載構造方法的缺陷,建立實例對象很容易,而且代碼也容易閱讀:
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setFat(27);
因爲javaBean自身有着很嚴重的缺點,構造過程被分到了幾個調用中,在構造過程當中java Bean可能處於不一致的狀態,類沒法僅僅經過檢驗構造方法參數的有效性來保證一致性,使用處於不一致狀態的對象將會致使失敗。另外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 Builder{
		//必須參數
		private final int servingSize;
		private final int servings;
		//可選參數
		private final int calories = 0;
		private final int fat = 0;
		private final int sodium = 0;
		private final int carbohydrate = 0;
		public Builder(int servingSize, int servings){
			this.servingSize = servingSize;
			this.servings = servings;
		}
		public Builder calories(int val){
			this.calories = val;
			return this;
		}
		public Builder fat(int val){
			this.fat = val;
			return this;
		}
		public Builder sodium(int val){
			this.sodium = val;
			return this;
		}
		public Builder carbohydrate(int val){
			this.carbohydrate = val;
			return this;
		}
		public NutritionFacts build(){
			return new NutritionFacts(this);
		}
	}
	private NutritionFacts(Builder builder){
		this.servingSize = builder.servingSize;
		this.servings = builder.servings;
		this.calories = builder.calories;
		this.fat = builder.fat;
		this.sodium = builder.sodium;
		this.carbohydrate = builder.carbohydrate;
	}
}
使用建造者模式建立實例對象:
NutritionFacts cocaCola = new NutritionFacts().Build(240, 8).calories(100).sodium(35).carbohydrate(27).build();
建造者模式能夠有多個可變參數,能夠利用建造器構建多個對象,參數能夠在建立時動態調整。

Builder建造者模式和AbstraceFactory抽象工廠模式的區別: ui

Builder建造者模式和AbstraceFactory抽象工廠模式很是相似,不少人常常分不清楚,區別以下: this

(1).抽象工廠模式中,每一次工廠物件被呼叫時都會傳回一個完整的產品物件,而使用端有可能會決定把這些產品組裝成一個更大的和複雜的產品,也有可能不會。工廠物件是沒有狀態的,不知道上一次構建的是哪個產品,也沒有將來的概念,不知道下一次構建的是哪個產品,更不知道本身構建的產品在更高層的產品結構藍圖中是什麼位置。   
(2). 建造者模式不一樣,建造模式的重點在指導者(Director)角色。指導者是有狀態的,它知道總體藍圖,知道上一次、這一次和下一次交給建造者(Builder)角色去構建的零件是什麼,以便可以將這些零件組裝成一個更大規模的產品。它一點一點地建造出一個複雜的產品,而這個產品的組裝程式就發生在指導者角色內部。建造者模式的使用端拿到的是一個完整的最後產品。   

 換言之,雖然抽象工廠模式與建造模式都是設計模式,可是抽象工廠模式處在更加具體的尺度上,而建造模式則處於更加宏觀的尺度上。一個系統能夠由一個建造模式和一個抽象工廠模式組成,使用端經過呼叫這個導演角色,間接地呼叫另外一個抽象工廠模式的工廠角色。工廠樣式傳回不一樣產品族的零件,而建造者模式則把它們組裝起來。   spa

JDK中建造者模式的應用: 線程

StringBuilder和StringBuffer的append()方法使用了建造者模式。 設計

相關文章
相關標籤/搜索