一、概念 將一個複雜對像的構建與它的表示分離,使得同樣的構建過程創建不同的表示,又叫建造模式。 生成器模式的重心在於分離構建演算法和具體的構造實現,從而使得構建演算法可以重用。採用不同的構建實現,產生不同的產品。所以生成器模式都會存在以下兩個部分: a.整體構建演算法 b.部件的構造和產品的裝配 二、模式 ...
一、概念
將一個複雜對像的構建與它的表示分離,使得同樣的構建過程創建不同的表示,又叫建造模式。
生成器模式的重心在於分離構建演算法和具體的構造實現,從而使得構建演算法可以重用。採用不同的構建實現,產生不同的產品。所以生成器模式都會存在以下兩個部分:
a.整體構建演算法
b.部件的構造和產品的裝配
二、模式動機
生成器模式主要的功能就是構建複雜的產品,且是細化的、分步驟的構建產品,生成器模式重在一步一步解決構造複雜對像的問題。
三、模式的結構
示意代碼:
/** * * @ClassName: Product * @Description: TODO(被構建的產品對像接品) * @author beteman6988 * @date 2017年10月1日 上午11:26:33 * */ public interface Product { }
/** * 成生器介面,定義構建一個產品對像所需要的各個部件的操作 * @ClassName: Builder * @author beteman6988 * @date 2017年10月1日 上午11:28:12 * */ public interface Builder { /** * 構建某個部件 * @Title: buildPart * @param * @return void * @throws */ public void buildPart(); /** * 獲取最終生成的產品對像 * @Title: getResult * @param @return * @return Product * @throws */ public Product getResult(); }
public class ConcreteBuilder implements Builder { //最終構建的產品 private Product resultProduct; /** * 獲取最終生成的產品 * @Title: getResult * @param @return * @return Product * @throws */ @Override public Product getResult() { return this.resultProduct; } @Override public void buildPart() { // TODO Auto-generated method stub } }
public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } /** * 指導生成器構建最終的產品對像 * @Title: construct * @param * @return void * @throws */ public void construct() { builder.buildPart(); builder.getResult(); } }
a.Builder:生成器介面,定義創建一個Product對像所需要的各個部件的操作。
b.ConcreteBuilder:具體生成器的實現,實現各個部件的創建,並負責組裝Product對像的各個部件,同時還提供一個讓用戶獲取組裝完畢後的產品對像的方法。
c.Director:指導者,抽像出來的整體構建演算法,主要用來使用Builder,以一個統一的過程來構建所需要的Product對像。
d.Product:產品,表示被生成器構建的複雜對像,包含多個部件。
四、模式樣例
以一次台式機組裝經歷為例,當我們去電腦城組裝電腦時,首先導購小妹妹會拿出一張列印好的空白配置報價單,我們在導購小妹的引導下,填寫(當然小導購小妹填寫)完了報價單後,然後組裝工程師小哥就會跟據這個報價單,去倉庫領取所有配件,然後就會將所有的配件組裝在一起,一個完整的computer就組裝好了,最後我們交錢拿電腦走人。
運用生成器模式對上述過程進行分析:
a.Product:導購小妹給我們的那個報價單可以說是一臺最終computer product的一個抽像,當我們填寫完一個一個完整的報價單後,可以說一個具體的compueter已經有了,
不過目前還是一堆零部件,要想得到一臺完整的computer,還需要一個組裝的過程。
b.Builder:我們的組裝工程師小哥,跟據不同的具體報價單,都要去倉庫忙一翻,要找到所有的部件,可以說只要有報價單,小哥都要將具體產口的每個部件都要找出來,少一個可以說都不行,這個可以說是一個完整電腦每個部件的抽像的建造(只是去倉庫的相關位置拿到相關部件)。
c.ConcreteBuilder:組裝工程師小哥跟據具體的報價單,去倉庫找到相應的配件,並對每個部件進行處理,該拆封的拆封,該插線的插線,然後依據一定的步驟組裝將所有配件組裝起來,組裝成一臺完整的電腦。
d.Director:電腦的組裝可以說有固定的套路,可以說這個套路適應於所有的電腦組裝,比如必須先有機箱,然後將主板裝到機箱上,然後將cpu裝到主板上,步驟不能亂。按這個套路,工程師小哥跟據不同的報價單組裝出不同的computer.
代碼如下:
public interface CBuilder { /** * 構建機箱 * @Title: buildBox * @param * @return void * @throws */ public void buildBox(); /** * 安裝主板 * @Title: buildMBoard * @param * @return void * @throws */ public void buildMBoard(); /** * 安裝CPU * @Title: buildCpu * @param * @return void * @throws */ public void buildCpu(); /** * 安裝記憶體 * @Title: buildMemory * @param * @return void * @throws */ public void buildMemory(); /** * 安裝硬碟 * @Title: buildHDisk * @param * @return void * @throws */ public void buildHDisk(); /** * 返回安裝完畢的電腦 * @Title: getComputer * @param @return * @return ComputerA * @throws */ public ComputerA getComputer(); }
public class ComputerABuilder implements CBuilder {
private ComputerA aComputer=new ComputerA(); @Override public void buildBox() { this.aComputer.setBox("MAtx"); } @Override public void buildMBoard() { this.aComputer.setmBoard("AsusMb"); } @Override public void buildCpu() { this.aComputer.setCpu("Intel CoreI7"); } @Override public void buildMemory() { this.aComputer.setMemory("King stone DDR4"); } @Override public void buildHDisk() { this.aComputer.sethDisk("West Hard Disk 1T"); } @Override public ComputerA getComputer() { // TODO Auto-generated method stub System.out.println("Box:"+this.aComputer.getBox()); System.out.println("MBoard:"+this.aComputer.getmBoard()); System.out.println("Cpu:"+this.aComputer.getCpu()); System.out.println("Memory:"+this.aComputer.getMemory()); System.out.println("HDisk:"+this.aComputer.gethDisk()); return aComputer; } }
public class ComputerA { private String box; private String mBoard; private String cpu; private String memory; private String hDisk; public ComputerA() { super(); } public String getBox() { return box; } public void setBox(String box) { this.box = box; } public String getmBoard() { return mBoard; } public void setmBoard(String mBoard) { this.mBoard = mBoard; } public String getCpu() { return cpu; } public void setCpu(String cpu) { this.cpu = cpu; } public String getMemory() { return memory; } public void setMemory(String memory) { this.memory = memory; } public String gethDisk() { return hDisk; } public void sethDisk(String hDisk) { this.hDisk = hDisk; } }
public class CDirector { private CBuilder theCBuilder; /** * @roseuid 59DB89BE02A1 */ public CDirector(CBuilder builder) { this.theCBuilder=builder; } /** * 獨立出來的構建過程 */ public void construct() { this.theCBuilder.buildBox(); this.theCBuilder.buildMBoard(); this.theCBuilder.buildCpu(); this.theCBuilder.buildMemory(); this.theCBuilder.buildHDisk(); this.theCBuilder.getComputer(); } }
public class Client { public static void main(String[] args) { CBuilder builder=new ComputerABuilder(); CDirector director=new CDirector(builder); director.construct(); } }
運行結果如下:
Box:MAtx
MBoard:AsusMb
Cpu:Intel CoreI7
Memory:King stone DDR4
HDisk:West Hard Disk 1T
五、模式的約束
對於以下情況應當使用生成器模式:
1.需要生成的產品對像有複雜的內部結構。每個內部成分可以是一個對像,也可以是產品的一個組成部分。
2.需要生產的產品的各個部件之間相互依賴,也就是一個部件的建造必須依賴另一個部件建造完成才能建造,生成器模式可以強制實行一種分步驟的建造過程。
3.在對像的創建過程中會使用到系統中的其它一些對像,這些對像在產品對像的創建過程中不易得到。
六、模式的變體與擴展
1.省略抽像生成器Builder角色,如果系統確定只會有一個具體生成器角色,那麼就可以省略掉抽像生成器角色,類圖如下:
2.省略指導者角色Director :如果抽像生成器Builder角色被省略,如上面的“1.”的情況,那麼Director存在的意義就不大了,該角色也可以進行省略,如下圖:
七、與其它模式的關係
1.生成器模式與工廠方法模式,這兩個模式可以組合使用。生成器模式的Builder實現中,通常需要選擇具體的部件實現。一個可行的方案就是實現為工廠方法,通常工廠方法來獲取具體的部件對像,然後再進行部件的裝配。
如下圖:
2.生成器模式與抽像工廠模式,這兩個模式是可以組合使用的,在生成器模式的Builder實現中,需要創建各個部件對像,而這些部件對像是有關聯的,通常是構成的是一個複雜對像的部件對像。也就是說,Builder實現中,需要獲取構成一個複雜對像的產品族,那自然就可以使用抽像工廠模式來實現,這樣一來抽像工廠負責了部件對像的創建,Builder實現裡面則主要負責產品對像的整體構建了。
如下圖:
其實創建模式和抽像工廠模式兩者還是有區別的,抽像工廠模式的主要目的是創建產品族,這個產品族裡面的單個產品就相當於是構成一個複雜對像的部件對像,抽像工廠對像創建完成後就立即返回整個產品族;而生成器的模式的主要目的是按照構造演算法,一步一步來構建一個複雜的產品對像,通常要等到整個構建過程結速後,才會得到最終的產品對像。
八、模式優缺點
生成器模式可以用同一個構建演算法構建出表現上完全不同的產品,實現產品的構建和產品的表現上的分離。生成器模式正是把產品的構建過程獨立出來,使它和具體產品的表現鬆散耦合,從而使得構建演算法可以重用,而具體產品表現可以擴展和切換,從產品表現維度很好的支持開閉原則。