在內蒙古這遼闊的草原上,放養著成千上萬的奶牛。蒙牛集團在這裡崛起,迅速搶占中國大半牛奶市場,造就了一個商業帝國。蒙牛集團牛奶生產流程大致是這樣的: 放養奶牛--->牛奶加工--->牛奶包裝--->銷售。經歷從放養奶牛到進行市場銷售這一系列環節,蒙牛牛奶才得以誕生。雖然生產流程比這個流程還復雜,但對客戶而言,根本不需要知道牛奶生產的細節,只需要到超市購買就行了。在設計模式中,也存在一個類似的模式,封裝了產品創建的一系列操作過程,客戶端無需知道這些操作流程就可以直接使用這個產品,稱之為建造者模式。
建造者模式是較為復雜的創建型模式,它將客戶端與包含多個組成部分(或部件)的復雜對象的創建過程分離,客戶端無須知道復雜對象的內部組成部分與裝配方式,只需要知道所需建造者的類型即可。它關注如何一步一步創建一個的復雜對象,不同的具體建造者定義了不同的創建過程,且具體建造者相互獨立,增加新的建造者非常方便,無須修改已有代碼,系統具有較好的擴展性。例如:用戶不需要知道電腦的具體制造流程,而直接使用電腦就可以了,電腦具體制造流程對用戶來說就相當於一個黑盒子。
建造者模式定義如下:
建造者模式(Builder Pattern):將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種對象創建型模式。
建造者模式一步一步創建一個復雜的對象,它允許用戶只通過指定復雜對象的類型和內容就可以構建它們,用戶不需要知道內部的具體構建細節。
建造者模式結構圖
在建造者模式結構圖中包含如下幾個角色:
Builder(抽象建造者):它為創建一個產品Product對象的各個部件指定抽象接口,在該接口中一般聲明兩類方法,一類方法是buildPartX(),它們用於創建復雜對象的各個部件;另一類方法是getResult(),它們用於返回復雜對象。Builder既可以是抽象類,也可以是接口。
ConcreteBuilder(具體建造者):它實現了Builder接口,實現各個部件的具體構造和裝配方法,定義並明確它所創建的復雜對象,也可以提供一個方法返回創建好的復雜產品對象。
Product(產品角色):它是被構建的復雜對象,包含多個組成部件,具體建造者創建該產品的內部表示並定義它的裝配過程。
Director(指揮者):指揮者又稱為導演類,它負責安排復雜對象的建造次序,指揮者與抽象建造者之間存在關聯關系,可以在其construct()建造方法中調用建造者對象的部件構造與裝配方法,完成復雜對象的建造。客戶端一般只需要與指揮者進行交互,在客戶端確定具體建造者的類型,並實例化具體建造者對象,然後通過指揮者類的構造函數或者Setter方法將該對象傳入指揮者類中。
在建造者模式的定義中提到了復雜對象,那麼什麼是復雜對象?簡單來說,復雜對象是指那些包含多個成員屬性的對象,這些成員屬性也稱為部件或零件,如汽車包括方向盤、發動機、輪胎等部件;電子郵件包括發件人、收件人、主題、內容、附件等部件;Socket數據包包含包頭、包體、包尾等部件;XML配置文件包含頭部信息、數據體、尾部信息等部件。
2、暴風影音播放器的設計與實現
現需要開發一款類似暴風影音的播放器,該播放軟件提供多種界面顯示模式,如完整模式、精簡模式、記憶模式等。在不同的顯示模式下主界面的組成元素有所差異,如在完整模式下將顯示菜單、播放列表、主窗口、控制條等;在精簡模式下只顯示主窗口和控制條;而在記憶模式下將顯示主窗口、控制條、收藏列表等。嘗試使用建造者模式設計該軟件。
#ifndef _PLAYER_H_ #define _PLAYER_H_ #include暴風影響播放器Cpp文件代碼如下:#include using namespace std; //播放器 class Player { private: string m_strMenu; //菜單欄 string m_strWindow; //主窗口 string m_strPlayList; //播放列表 string m_strControlBar; //進度條 string m_strCollectList; //收藏列表 public: //設置部件 void SetMenu(string strMenu); void SetWindow(string strWindow); void SetPlayList(string strPlayList); void SetControlBar(string strControlBar); void SetCollectList(string strCollectList); //獲取各部件 string GetMenu(); string GetWindow(); string GetPlayList(); string GetControlBar(); string GetCollectList(); //顯示播放器窗口包含的部件 void Display(); }; #endif
#include "Player.h" //設置主菜單部件 void Player::SetMenu(string strMenu) { m_strMenu = strMenu; } //設置主窗口部件 void Player::SetWindow(string strWindow) { m_strWindow = strWindow; } //設計播放列表部件 void Player::SetPlayList(string strPlayList) { m_strPlayList = strPlayList; } //設置滾動條部件 void Player::SetControlBar(string strControlBar) { m_strControlBar = strControlBar; } //設置收藏列表部件 void Player::SetCollectList(string strCollectList) { m_strCollectList = strCollectList; } //獲取主菜單部件 string Player::GetMenu() { return m_strMenu; } //獲取主窗口部件 string Player::GetWindow() { return m_strWindow; } //獲取播放列表部件 string Player::GetPlayList() { return m_strPlayList; } //獲取滾動條部件 string Player::GetControlBar() { return m_strControlBar; } //獲取收藏列表部件 string Player::GetCollectList() { return m_strCollectList; } //顯示播放器窗口包含的部件 void Player::Display() { cout << "---" << m_strWindow << endl; cout << "---" << m_strMenu << endl; cout << "---" << m_strPlayList << endl; cout << "---" << m_strControlBar << endl; cout << "---" << m_strCollectList << endl << endl; }暴風影音播放器能在完整模式、精簡模式、記憶模式三種模式下播放,各播放模式下,暴風影音的部件不相同。考慮到擴展性,可以定義一個抽象播放模式類,該抽象類中定義了一系列創建具體播放部件的方法。具體的三種播放模式繼承於這個抽象播放模式類。 播放模式.h頭文件代碼如下:
#ifndef _PLAY_PATTERN_H_ #define _PLAY_PATTERN_H_ #include播放模式Cpp文件代碼如下:#include #include "Player.h" using namespace std; //抽象播放模式 class PlayPattern { protected: //具體產品(播放器) Player * m_pPlayer; public: PlayPattern() { m_pPlayer = new Player(); } ~PlayPattern() { if( NULL != m_pPlayer ) { delete m_pPlayer; m_pPlayer = NULL; } } //制造播放窗口 virtual void BuildWindow() = 0; //制造播放菜單 virtual void BuildMenu() = 0; //制造播放列表 virtual void BuildPlayList() = 0; //制造播放進度條 virtual void BuildControlBar() = 0; //制造收藏列表 virtual void BuildCollectList() = 0; //獲取產品(播放器) Player * GetPlayer() { return m_pPlayer; } }; //完整播放模式 class FullPattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); }; //精簡播放模式 class SimplePattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); }; //記憶播放模式 class MemoryPattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); }; #endif
#include "PlayPattern.h" //制造播放窗口 void FullPattern::BuildWindow() { m_pPlayer->SetWindow("主界面窗口"); } //制造播放菜單 void FullPattern::BuildMenu() { m_pPlayer->SetMenu("主菜單"); } //制造播放列表 void FullPattern::BuildPlayList() { m_pPlayer->SetPlayList("播放列表"); } //制造播放進度條 void FullPattern::BuildControlBar() { m_pPlayer->SetControlBar("進度條"); } //制造收藏列表 void FullPattern::BuildCollectList() { m_pPlayer->SetCollectList(" "); } ////////////////精簡模式/////////////////////////////// void SimplePattern::BuildWindow() { m_pPlayer->SetWindow("主界面窗口"); } void SimplePattern::BuildMenu() { m_pPlayer->SetMenu(" "); } void SimplePattern::BuildPlayList() { m_pPlayer->SetPlayList(" "); } void SimplePattern::BuildControlBar() { m_pPlayer->SetControlBar("進度條"); } void SimplePattern::BuildCollectList() { m_pPlayer->SetCollectList(" "); } /////////////////記憶模式//////////////////////////////// void MemoryPattern::BuildWindow() { m_pPlayer->SetWindow("主界面窗口"); } void MemoryPattern::BuildMenu() { m_pPlayer->SetMenu(" "); } void MemoryPattern::BuildPlayList() { m_pPlayer->SetPlayList(" "); } void MemoryPattern::BuildControlBar() { m_pPlayer->SetControlBar("進度條"); } void MemoryPattern::BuildCollectList() { m_pPlayer->SetCollectList("收藏列表"); }在建造者模式的結構中還引入了一個指揮者類Director,用於控制產品的創建過程。本例中ContructManage就是播放器指揮類。用戶需要哪種類型的播放模式,只需要創建一個具體的播放模式,然後把這個播放模式傳入到播放器指揮者中就可以了,由播放器指揮者處理一系列過程的建造。
#ifndef _CONTRUCT_MANAGE_H_ #define _CONTRUCT_MANAGE_H_ #include "PlayPattern.h" #include "Player.h" //建造管理器 class ContructManage { private: //具體建造者 PlayPattern * m_pPlayPattern; public: //設置播放模式 void SetPlayPattern(PlayPattern * pPlayPattern); //封裝建造過程 Player * Construct(); }; #endif暴風影音播放器指揮者類Cpp文件實現如下:
#include "ContructManage.h" //設置播放模式 void ContructManage::SetPlayPattern(PlayPattern * pPlayPattern) { m_pPlayPattern = pPlayPattern; } //封裝建造過程 Player * ContructManage::Construct() { m_pPlayPattern->BuildWindow(); m_pPlayPattern->BuildMenu(); m_pPlayPattern->BuildPlayList(); m_pPlayPattern->BuildControlBar(); m_pPlayPattern->BuildCollectList(); Player * pPlayer = m_pPlayPattern->GetPlayer(); return pPlayer; }測試文件實現代碼如下:
#include編譯並執行,程序結果如下: 編程,客戶端根據需要傳入具體的建造者類型,指揮者將指導具體建造者一步一步構造一個完整的產品(逐步調用具體建造者的buildX()方法),相同的構造過程可以創建完全不同的產品。在暴風影音播放器實例中,如果需要更換具體的播放模式,只需要把具體播放模式傳入到播放器指揮者中即可,可以隨時切換播放模式;如果需要增加新的播放模式,可以增加一個新的播放模式類作為抽象播放模式子類,並把該播放模式傳入到播放器指揮者中,原有代碼無須修改,完全符合“開閉原則”。#include "ContructManage.h" #include "PlayPattern.h" #include "Player.h" using namespace std; int main() { /***********************創建建造管理器**********************/ ContructManage * pContructManage = new ContructManage(); Player * pPlayer = NULL; /***********************完整播放模式************************/ PlayPattern * pFullPattern = new FullPattern(); cout << "完整播放模式:" << endl; pContructManage->SetPlayPattern(pFullPattern); pPlayer = pContructManage->Construct(); pPlayer->Display(); /***********************精簡播放模式************************/ PlayPattern * pSimplePattern = new SimplePattern(); cout << "精簡播放模式:" << endl; pContructManage->SetPlayPattern(pSimplePattern); pPlayer = pContructManage->Construct(); pPlayer->Display(); /***********************記憶播放模式************************/ PlayPattern * pMemoryPattern = new MemoryPattern(); cout << "記憶播放模式:" << endl; pContructManage->SetPlayPattern(pMemoryPattern); pPlayer = pContructManage->Construct(); pPlayer->Display(); /***********************銷毀操作****************************/ cout << endl; delete pFullPattern; pFullPattern = NULL; delete pSimplePattern; pSimplePattern = NULL; delete pMemoryPattern; pMemoryPattern = NULL; delete pContructManage; pContructManage = NULL; return 0; }