1. 什麼是生成器模式?
《Head First設計模式》中定義:封裝一個產品的構造過程,並允許按步驟構造。
生成器模式(Builder Pattern)將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。生成器模式是對象創建型模式,又叫建造者模式。
生成器模式針對的是複雜對象的創建。它可以將複雜對象的建造過程抽象出來,使這個抽象過程的不同實現方法可以構造不同表現(屬性)的對象。
舉個例子加深理解:
比如我們要去法拉利私人定製一款汽車,我們只需要向服務商提需求,然後服務商就會協調生產車間生產汽車。定製的汽車就是一個複雜的對象,其中包含空調系統、電子系統。動力系統等,而每一個子系統的生產都是複雜且非常耗時的。如果全部工作都交給一個車間來生產的話(傳統創建對象),可能等我老了這個車還沒造出來。如果將生產過程各自分工(創建過程抽象出來),然後由一個協調部門負責組裝的話,這樣汽車建造速度將大大提高,而且私人定製也比較容易(想怎麼組裝就怎麼組裝),裝上普通動力系統的就是法拉利轎車,裝上強勁動力系統就是法拉利跑車(不同的表現)。這個協調部門就是Director角色。
2. 角色
圖片來源於網絡
抽象建造者(Builder):可以是接口也可以是抽象類。爲創建產品Product對象的各個組件指定抽象方法。一般有兩類方法,一類是創建複雜對象的各個組件(buildPartA、buildPartB...)和另一類返回創建的複雜對象(getResult)。
具體建造者(ConcreteBuilder):Builder的具體實現類,可以有多個,每一個提供複雜對象各個組件的一種創建和裝配方法,最終返回創建好的複雜對象。
產品角色(Product):它是被構建的複雜對象,包含多個組成部件,具體建造者創建該產品的內部表示並定義它的裝配過程
指揮者角色(Director):Director負責安排複雜對象Product的建造次序。Director和Builder存在關聯關係,通過construct方法調用Builder中的創建方法完成複雜對象的創建。客戶端只需要和Director聯繫。
3. 優點
(1)客戶端不需要知道複雜對象的創建細節,將對象和創建過程解耦,使相同的創建過程可以創建不同的對象。
(2)每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可創建不同的產品對象。由於指揮者類針對抽象建造者編程,增加新的具體建造者無須修改原有代碼,系統擴展方便,符合“開閉原則”。
(3)可以更加精細地控制產品的創建過程。將複雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
4. 缺點
(1)使用生成器模式必須要求Product類具有相似的結構,如果差異性太大就無法使用該模式,因此具有一定的侷限性。
(2)將創建過程抽象出來會造成類文件增加。
5. 使用場景
(1)要生成的產品對象有複雜的內部結構,包含多個成員屬性。
(2)將創建過程分離開,使相同的創建過程能創建不同的產品對象。
(3)產品對象內部組件之間存在相互依賴,且組件創建具有一定的順序。
6. 示例代碼
(1)抽象建造者類
/**
*抽象建造者
*/
public abstract class AbstractCarBuilder {
//產品的引用
protected Car car;
public AbstractCarBuilder() {
this.car=new Car();
}
public abstract void buildAcSystem();
public abstract void buildPowerSystem();
public abstract void buildElectronicSystem();
public Car getCar(){
return car;
}
}
(2)具體建造者類
/**
* 普通汽車建造者
*/
public class LittleCarBuilder extends AbstractCarBuilder {
@Override
public void buildAcSystem() {
this.car.setAcSystem("海爾空調系統");
}
@Override
public void buildPowerSystem() {
this.car.setPowerSystem("1.6自然吸氣系統");
}
@Override
public void buildElectronicSystem() {
this.car.setElectronicSystem("華爲電子系統");
}
}
/**
* 跑車建造者
*/
public class SportsCarBuilder extends AbstractCarBuilder {
@Override
public void buildAcSystem() {
this.car.setAcSystem("格力空調系統");
}
@Override
public void buildPowerSystem() {
this.car.setPowerSystem("4.0T渦輪增壓系統");
}
@Override
public void buildElectronicSystem() {
this.car.setElectronicSystem("西門子電子系統");
}
}
(3)產品類
/**
*產品類
*其中可能存在許多創建過程比較複雜的其他對象
*/
public class Car {
//空調系統組件(可以是一個對象)
private String acSystem;
//動力系統組件
private String powerSystem;
//電子系統組件
private String electronicSystem;
public String getAcSystem() {
return acSystem;
}
public void setAcSystem(String acSystem) {
this.acSystem = acSystem;
}
public String getPowerSystem() {
return powerSystem;
}
public void setPowerSystem(String powerSystem) {
this.powerSystem = powerSystem;
}
public String getElectronicSystem() {
return electronicSystem;
}
public void setElectronicSystem(String electronicSystem) {
this.electronicSystem = electronicSystem;
}
@Override
public String toString() {
return "Car [acSystem=" + acSystem + ", powerSystem=" + powerSystem + ", electronicSystem=" + electronicSystem
+ "]";
}
}
(4)指揮者類
/**
*car建造指揮者
*/
public class CarDirector {
private AbstractCarBuilder acb;
public CarDirector(AbstractCarBuilder acb) {
this.acb=acb;
}
public void setAcb(AbstractCarBuilder acb) {
this.acb = acb;
}
public Car constructCar(){
//此處可以規定組件創建順序
acb.buildAcSystem();
acb.buildElectronicSystem();
acb.buildPowerSystem();
return acb.getCar();
}
}
(5)測試
public class Client {
public static void main(String[] args) {
CarDirector director=new CarDirector(new SportsCarBuilder());
Car car1=director.constructCar();
System.out.println(car1.toString());
System.out.println("---------------");
director.setAcb(new LittleCarBuilder());
Car car2=director.constructCar();
System.out.println(car2.toString());
}
}
(6)測試結果
Car [acSystem=格力空調系統, powerSystem=4.0T渦輪增壓系統, electronicSystem=西門子電子系統]
---------------
Car [acSystem=海爾空調系統, powerSystem=1.6自然吸氣系統, electronicSystem=華爲電子系統]
7. 生成器模式和工廠模式的對比
圖片來源於網絡
【四川樂山程序員聯盟,歡迎大家加羣相互交流學習5 7 1 8 1 4 7 4 3】