一、 建造者(Builder)模式
建造者模式可以將一個產品的內部表象與產品的產生過程分割開來,從而可以使一個建造過程產生具有不同的內部表象的產品對象。
對象性質的建造
有些情況下,一個對象會有一些重要的性質,在它們沒有恰當的值之前,對象不能作為一個完整的產品使用。比如,一個電子郵件有寄件者地址、收件者地址、主題、內容、附錄等部分,而在最起碼的收件者地址未被賦值之前,這個電子郵件不能發出。
再舉一個例子:想象一下像電腦這樣一個複雜的產品。每台電腦都有很多部分組成,包括CPU,光碟機,顯卡,記憶體.......最終的電腦產品需要按一定的順序,先安裝CPU然後記憶體等等,在組裝過程沒有結束之前,電腦是無法使用的。由於這一組裝過程可能很複雜,而且可能會經常變動。那麼就有必要將這易變的過程抽象出一個外部電腦組裝者來負責產品的組裝過程。另外,客戶對於電腦產品肯定會有一些偏好,比如某些人喜歡DELL電腦,有些人喜歡IBM電腦,這些電腦生產者的組裝產品的方式幾乎雷同,也就是說針對客戶的不同需要,電腦組裝者的構造過程可以適合於不同的生產者。
對於這樣的有多個零件組成的複雜產品的組裝過程,就可以使用Builder建造者模式來完成。
有些情況下,一個對象的一些性質必須按照某個順序賦值才有意義。在某個性質沒有賦值之前,另一個性質則無法賦值。這些情況使得性質本身的建造涉及到複雜的商業邏輯。這時候,此對象相當於一個有待建造的產品,而對象的這些性質相當於產品的零件,建造產品的過程就是組合零件的過程。由於組合零件的過程很複雜,因此,這些"零件"的組合過程往往被"外部化"到一個稱作建造者的對象裡,建造者返還給用戶端的是一個全部零件都建造完畢的產品對象。
命名的考慮
之所以使用"建造者"而沒有用"產生器"就是因為用零件生產產品,"建造"更為合適,"建立"或"產生"不太恰當。
二、 Builder模式的結構:
建造者(Builder)角色:給出一個抽象介面,以規範產品對象的各個組成成分的建造。一般而言,此介面獨立於應用程式的商業邏輯。模式中直接建立產品對象的是具體建造者(ConcreteBuilder)角色。具體建造者類必須實現這個介面所要求的方法:一個是建造方法,另一個是結果返還方法。
具體建造者(Concrete Builder)角色:擔任這個角色的是於應用程式緊密相關的類,它們在應用程式調用下建立產品執行個體。這個角色主要完成的任務包括:
- 實現Builder角色提供的介面,一步一步完成建立產品執行個體的過程。
- 在建造過程完成後,提供產品的執行個體。 指導者(Director)角色:擔任這個角色的類調用具體建造者角色以建立產品對象。導演者並沒有產品類的具體知識,真正擁有產品類的具體知識的是具體建造者對象。
產品(Product)角色:產品便是建造中的複雜物件。
指導者角色是於用戶端打交道的角色。導演者角色將用戶端建立產品的請求劃分為對各個零件的建造請求,再將這些請求委派給具體建造者角色。具體建造者角色是做具體建造工作的,但卻不為用戶端所知。
三、 程式舉例:
該程式示範了Builder模式一步一步完成構件複雜產品的過程。使用者可以控制產生過程以及產生不同對象。
import java.util.ArrayList;/** * 常見設計模式之【建造模式】 * @author Potter */public class BuilderTest {/** * @param args */public static void main(String[] args) {BuilderTest test =new BuilderTest();BuilderTest.Director director=test.new Director();BuilderTest.Builder b1=test.new CounCreteBuilder1();//Construct products:建造產品director.Counstruct(b1);Product p1=b1.GetResult();p1.show();}//Director:指導者角色class Director{//methodspublic void Counstruct(Builder builder){builder.BuildPartA();builder.BuildPartB();}}//Builder:建造者角色abstract class Builder{//methodsabstract public void BuildPartA();abstract public void BuildPartB();abstract public Product GetResult();}//CounCreteBuilder1:具體建造者角色class CounCreteBuilder1 extends Builder{private Product product=new Product();@Overridepublic void BuildPartA() {// TODO Auto-generated method stubproduct.Add("partA");}@Overridepublic void BuildPartB() {// TODO Auto-generated method stubproduct.Add("partB");}@Overridepublic Product GetResult() {// TODO Auto-generated method stubreturn product;}}//Product產品角色class Product{//Fields ArrayList<String> parts =new ArrayList<String>();//methodspublic void Add(String part){parts.add(part);}public void show(){System.out.println("Product Parts----");for(String part:parts){System.out.println(""+part);}}}}
四、 建造者模式的活動序列:
用戶端負責建立指導者和具體建造者對象。然後,客戶把具體建造者對象交給指導者。客戶一聲令下,指導者操縱建造者開始建立產品。當產品建立完成後,建造者把產品返還給用戶端。
五、 建造者模式的演化
建造者模式在使用的過程中可以演化出多種形式。
省略抽象建造者角色
如果系統中只需要一個具體建造者的話,可以省略掉抽象建造者。這時代碼可能如下:
import java.util.ArrayList;/** * 常見設計模式之【建造模式】 * @author Potter */public class BuilderTest {/** * @param args */public static void main(String[] args) {BuilderTest test =new BuilderTest();BuilderTest.Director director=test.new Director();//Construct products:建造產品director.counstruct();Product p1=director.builder.getResult();p1.show();}//Director:指導者角色class Director{private CounCreteBuilder1 builder=new CounCreteBuilder1();//methodspublic void counstruct(){builder.buildPartA();builder.buildPartB();}}//CounCreteBuilder1:具體建造者角色class CounCreteBuilder1 {private Product product=new Product();public void buildPartA() {// TODO Auto-generated method stubproduct.add("partA");}public void buildPartB() {// TODO Auto-generated method stubproduct.add("partB");}public Product getResult() {// TODO Auto-generated method stubreturn product;}}//Product產品角色class Product{//Fields ArrayList<String> parts =new ArrayList<String>();//methodspublic void add(String part){parts.add(part);}public void show(){System.out.println("Product Parts----");for(String part:parts){System.out.println(""+part);}}}}
省略指導者角色
在具體建造者只有一個的情況下,如果抽象建造者角色已經被省略掉,那麼還可以省略掉指導者角色。讓Builder角色自己扮演指導者與建造者雙重角色。這時代碼可能如下:
import java.util.ArrayList;/** * 常見設計模式之【建造模式】 * @author Potter */public class BuilderTest {/** * @param args */public static void main(String[] args) {BuilderTest test =new BuilderTest();CounCreteBuilder1 builder=test.new CounCreteBuilder1();builder.counstruct();Product p1=builder.getResult();p1.show();}//CounCreteBuilder1:具體建造者角色class CounCreteBuilder1 {private Product product=new Product();public void buildPartA() {// TODO Auto-generated method stubproduct.add("partA");}public void buildPartB() {// TODO Auto-generated method stubproduct.add("partB");}public Product getResult() {// TODO Auto-generated method stubreturn product;}public void counstruct(){buildPartA();buildPartB();}}//Product產品角色class Product{//Fields ArrayList<String> parts =new ArrayList<String>();//methodspublic void add(String part){parts.add(part);}public void show(){System.out.println("Product Parts----");for(String part:parts){System.out.println(""+part);}}}}
六、 在什麼情況下使用建造者模式
以下情況應當使用建造者模式:
1、 需要產生的產品對象有複雜的內部結構。
2、 需要產生的產品對象的屬性相互依賴,建造者模式可以強迫產生順序。
3、 在對象建立過程中會使用到系統中的一些其它對象,這些對象在產品對象的建立過程中不易得到。
使用建造者模式主要有以下效果:
1、 建造模式的使用使得產品的內部表象可以獨立的變化。使用建造者模式可以使用戶端不必知道產品內部組成的細節。
2、 每一個Builder都相對獨立,而與其它的Builder無關。
3、 模式所建造的最終產品更易於控制。
參看文章:
http://archive.cnblogs.com/a/1133133/
相關資料:
http://www.cnblogs.com/abcdwxc/archive/2007/08/30/876133.html