生成器模式的核心是 ** 當構建生成一個對象的時候泪漂,需要包含多個步驟,雖然每個步驟具體的實現不同歪泳,但是都遵循一定的流程與規(guī)則 **
舉個例子萝勤,我們如果構建生成一臺電腦,那么我們可能需要這么幾個步驟
- 需要一個主機
- 需要一個顯示器
- 需要一個鍵盤
- 需要一個鼠標
- 需要音響等
雖然我們具體在構建一臺主機的時候呐伞,每個對象的實際步驟是不一樣的敌卓,比如,有的對象構建了i7cpu的主機伶氢,有的對象構建了i5cpu的主機趟径,有的對象構建了普通鍵盤,有的對象構建了機械鍵盤等癣防。
但不管怎樣蜗巧,你總是需要經過一個步驟就是構建一臺主機,一臺鍵盤蕾盯。
對于這個例子幕屹,我們就可以使用生成器模式來生成一臺電腦,他需要通過多個步驟來生成级遭。
所以香嗓,我們可以將生成器模式理解為,假設我們有一個對象需要建立装畅,這個對象是由多個組件(Component)組合而成靠娱,每個組件的建立都比較復雜,但運用組件來建立所需的對象非常簡單掠兄,所以我們就可以將構建復雜組件的步驟與運用組件構建對象分離像云,使用builder模式可以建立锌雀。
生成器模式的類圖如下:
下面我們就根據這個例子來實現一個生成器模式,生成一臺電腦
首先我們需要一個電腦類:
package Builder;
public class Computer {
public String master;
public String screen;
public String keyboard;
public String mouse;
public String audio;
public void setMaster(String master) {
this.master = master;
}
public void setScreen(String screen) {
this.screen = screen;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
public void setMouse(String mouse) {
this.mouse = mouse;
}
public void setAudio(String audio) {
this.audio = audio;
}
}
然后我們建立一個抽象的builder類:
package Builder;
public abstract class ComputerBuilder {
protected Computer computer;
public Computer getComputer() {
return computer;
}
public void buildComputer() {
computer = new Computer();
System.out.println("生成了一臺電腦Q肝堋R改妗!");
}
public abstract void buildMaster();
public abstract void buildScreen();
public abstract void buildKeyboard();
public abstract void buildMouse();
public abstract void buildAudio();
}
然后我們實現兩個具體的builder類侈贷,分別是惠普電腦的builder和戴爾電腦的builder
package Builder;
public class HPComputerBuilder extends ComputerBuilder {
@Override
public void buildMaster() {
// TODO Auto-generated method stub
computer.setMaster("i7,16g,512SSD,1060");
System.out.println("(i7,16g,512SSD,1060)的惠普主機");
}
@Override
public void buildScreen() {
// TODO Auto-generated method stub
computer.setScreen("1080p");
System.out.println("(1080p)的惠普顯示屏");
}
@Override
public void buildKeyboard() {
// TODO Auto-generated method stub
computer.setKeyboard("cherry 青軸機械鍵盤");
System.out.println("(cherry 青軸機械鍵盤)的鍵盤");
}
@Override
public void buildMouse() {
// TODO Auto-generated method stub
computer.setMouse("MI 鼠標");
System.out.println("(MI 鼠標)的鼠標");
}
@Override
public void buildAudio() {
// TODO Auto-generated method stub
computer.setAudio("飛利浦 音響");
System.out.println("(飛利浦 音響)的音響");
}
}
package Builder;
public class DELLComputerBuilder extends ComputerBuilder {
@Override
public void buildMaster() {
// TODO Auto-generated method stub
computer.setMaster("i7,32g,1TSSD,1060");
System.out.println("(i7,32g,1TSSD,1060)的戴爾主機");
}
@Override
public void buildScreen() {
// TODO Auto-generated method stub
computer.setScreen("4k");
System.out.println("(4k)的dell顯示屏");
}
@Override
public void buildKeyboard() {
// TODO Auto-generated method stub
computer.setKeyboard("cherry 黑軸機械鍵盤");
System.out.println("(cherry 黑軸機械鍵盤)的鍵盤");
}
@Override
public void buildMouse() {
// TODO Auto-generated method stub
computer.setMouse("MI 鼠標");
System.out.println("(MI 鼠標)的鼠標");
}
@Override
public void buildAudio() {
// TODO Auto-generated method stub
computer.setAudio("飛利浦 音響");
System.out.println("(飛利浦 音響)的音響");
}
}
然后我們實現一個director類:
package Builder;
public class Director {
private ComputerBuilder computerBuilder;
public void setComputerBuilder(ComputerBuilder computerBuilder) {
this.computerBuilder = computerBuilder;
}
public Computer getComputer() {
return computerBuilder.getComputer();
}
public void constructComputer() {
computerBuilder.buildComputer();
computerBuilder.buildMaster();
computerBuilder.buildScreen();
computerBuilder.buildKeyboard();
computerBuilder.buildMouse();
computerBuilder.buildAudio();
}
}
最后我們測試一下代碼:
package Builder;
public class ComputerCustomer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Director director = new Director();
ComputerBuilder hp = new HPComputerBuilder();
director.setComputerBuilder(hp);
director.constructComputer();
//get the pc
Computer pc = director.getComputer();
}
}
生成器模式的優(yōu)缺點
優(yōu)點
- 將一個對象分解為各個組件
- 將對象組件的構造封裝起來
- 可以控制整個對象的生成過程
缺點
對不同類型的對象需要實現不同的具體構造器的類惩歉,這可能回答大大增加類的數量
生成器模式的實際應用
Builder pattern has been used in a lot of libraries. However, there is a common mistake here. Consider the following example of StringBuilder which is a class from Java standard library. Does it utilize the Builder pattern?
生成器模式在許多類庫中都使用了。但是嚴格來說俏蛮,卻有些錯誤撑蚌。
比如這個例子,我們考慮java標準庫中的StringBuilder類搏屑,它使用了生成器模式么争涌?
StringBuilder strBuilder= new StringBuilder();
strBuilder.append("one");
strBuilder.append("two");
strBuilder.append("three");
String str= strBuilder.toString();
在標準庫中,StringBuilder繼承自AbstractStringBuilder
append方法是這個生成過程中的一步辣恋,就像我們構建電腦時亮垫,先構建主機這樣的步驟一樣。
toString方法也是生成過程中的一步伟骨,而且是構建過程中的最后一步饮潦。然而,這里的不同是沒有director携狭,所以嚴格來說這不是一個標準的生成器模式继蜡。我們程序的調用者好像就是director可以生成我們自己的String。
生成器模式與工廠模式的不同
生成器模式構建對象的時候暑中,對象通常構建的過程中需要多個步驟壹瘟,就像我們例子中的先有主機鲫剿,再有顯示屏鳄逾,再有鼠標等等,生成器模式的作用就是將這些復雜的構建過程封裝起來灵莲。
工廠模式構建對象的時候通常就只有一個步驟雕凹,調用一個工廠方法就可以生成一個對象。