生活中有著很多的Builder的例子,個人覺得大學生活就是一個Builder模式的最好體驗:要完成大學教育,一般將大學教育過程分成4個學期進行,因此沒有學習可以看作是構建完整大學教育的一個部分構建過程,每個人經過這4年的(4個階段)構建過程得到的最後的結果不一樣,因為可能在四個階段的構建中引入了很多的參數(每個人的機會和際遇不完全相同)。
Builder模式要解決的也正是這樣的問題:當我們要創建的對象很復雜的時候(通常是由很多其他的對象組合而成),我們要要復雜對象的創建過程和這個對象的表示(展示)分離開來,這樣做的好處就是通過一步步的進行復雜對象的構建,由於在每一步的構造過程中可以引入參數,使得經過相同的步驟創建最後得到的對象的展示不一樣。
Builder模式的UML結構圖如圖1所示:
Builder模式的關鍵是其中的Director對象並不直接返回對象,而是通過一步步(BuildPartA,BuildPartB,BuildPartC)來一步步進行對象的創建。當然這裡Director可以提供一個默認的返回對象的接口(即返回通用的復雜對象的創建,即不指定或者特定唯一指定BuildPart中的參數)。
Builder模式的實現基於以下幾個面向對象的設計原則:
1)把變化的部分提取出來形成一個基類和對應的接口函數,在這裡不會變化的是都會創建PartA和PartB,變化的則是不同的創建方法,於是就抽取出這裡的Builder基類和BuildPartA,BuildPartB接口函數
2)采用聚合的方式聚合了會發生變化的基類,就是這裡Director聚合了Builder類的指針.
以上,通過兩個派生類ConcreteBuilder1、ConcreteBuilder2定義了兩種不同的建造細節(建造步驟是一樣的,由Construct函數確定),通過兩個派生類所建造出來的對象,對外部所展現出來的屬性或者功能是不一樣的,由各自Builder派生類中的建造方法(BuildPartA、BuildPartB、BuildPartC)決定。
Builder.h
#ifndef _BUILDER_H_ #define _BUILDER_H_ #include#include using namespace std; //產品類 class Product { private: string m_partA; string m_partB; string m_partC; public: void setPartA(const string& s); void setPartB(const string& s); void setPartC(const string& s); Product(); ~Product(); }; //抽象Builder基類,定義不同部分的創建接口 class Builder { public: virtual void BuildPartA()=0; virtual void BuildPartB()=0; virtual void BuildPartC()=0; virtual Product* GetProduct()=0; Builder(); virtual ~Builder(); }; // Builder的派生類,實現BuilderPartA和BuilderPartB和BuildPartC接口函數 class ConcreteBuilder1:public Builder { public: ConcreteBuilder1(); ~ConcreteBuilder1(); virtual void BuildPartA(); virtual void BuildPartB(); virtual void BuildPartC(); virtual Product* GetProduct(); private: Product* m_pProduct; }; // Builder的派生類,實現BuilderPartA和BuilderPartB和BuildPartC接口函數 class ConcreteBuilder2:public Builder { public: ConcreteBuilder2(); ~ConcreteBuilder2(); virtual void BuildPartA(); virtual void BuildPartB(); virtual void BuildPartC(); virtual Product* GetProduct(); private: Product* m_pProduct; }; //ConcreteBuilder1與ConcreteBuilder2是Builder的兩個派生類,用於實現兩種不同的建造細節 // 使用Builder構建產品,構建產品的過程都一致,但是不同的builder有不同的實現 // 這個不同的實現通過不同的Builder派生類來實現,存有一個Builder的指針,通過這個來實現多態調用 class Director { public: Director(Builder* pBuilder); ~Director(); //Construct函數定義一個對象的整個構建過程,不同的部分之間的裝配方式都是一致的, //首先構建PartA其次是PartB,只是根據不同的構建者會有不同的表示 void Construct(); //void Construct(const string& buildPara); private: Builder* m_pBuilder; }; #endif
Director.cpp
#include "Builder.h" #include#include using namespace std; Product::~Product() { } Product::Product() {} void Product::setPartA(const string& s) { this->m_partA = s; } void Product::setPartB(const string& s) { this->m_partB = s; } void Product::setPartC(const string& s) { this->m_partC = s; } Builder::Builder() {} Builder::~Builder() {} ConcreteBuilder1::ConcreteBuilder1() { this->m_pProduct = new Product(); cout<<"Create empty product!"< m_pProduct->setPartA("A"); cout<<"BuildPartA"< m_pProduct->setPartB("B"); cout<<"BuildPartB"< m_pProduct->setPartC("C"); cout<<"BuildPartC"< m_pProduct; } ConcreteBuilder1::~ConcreteBuilder1() { delete this->m_pProduct; this->m_pProduct = NULL; } ConcreteBuilder2::ConcreteBuilder2() { this->m_pProduct = new Product(); cout<<"Create empty product!"< m_pProduct->setPartA("A"); cout<<"BuildPartA"< m_pProduct->setPartB("B"); cout<<"BuildPartB"< m_pProduct->setPartC("C"); cout<<"BuildPartC"< m_pProduct; } ConcreteBuilder2::~ConcreteBuilder2() { delete this->m_pProduct; this->m_pProduct = NULL; } Director::Director(Builder* pBuilder) { this->m_pBuilder = pBuilder; } void Director::Construct() { this->m_pBuilder->BuildPartA(); this->m_pBuilder->BuildPartB(); this->m_pBuilder->BuildPartC(); } Director::~Director() { delete this->m_pBuilder; this->m_pBuilder = NULL; }
#include "Builder.h" #includeusing namespace std; int main() { Director* pDirector = new Director(new ConcreteBuilder1()); pDirector->Construct(); Director* pDirector1 = new Director(new ConcreteBuilder2()); pDirector1->Construct(); return 0; }
建造者模式和工廠模式使用很相似,但也有區別:
建造者模式最主要功能是基本方法的調用順序安排,也就是這些基本方法已經實現了;而工廠方法則重點是創建,你要什麼對象我創造一個對象出來,組裝順序則不是他關心的。
建造者模式使用的場景,一是產品類非常的復雜,或者產品類中的調用順序不同產生了不同的效能,這個時候使用建造者模式是非常合適。