4、引入鉤子方法的建造者模式
建造者模式除了逐步構建一個復雜產品對象外,還可以通過Director類來更加精細地控制產品的創建過程,例如增加一類稱之為鉤子方法(HookMethod)的特殊方法來控制是否對某個buildPartX()的調用,也就是判斷產品中某個部件是否需要被建造。鉤子方法的返回類型通常為boolean類型,方法名一般為isXXX(),鉤子方法定義在抽象建造者類中。在抽象建造者類中提供鉤子方法的默認實現,具體建造者類如果不需要建造某個部件,則該建造者類覆蓋抽象建造者類的鉤子方法。
暴風影音播放器是具體的產品,實現代碼和C++設計模式之建造者模式(一)博客一樣,這裡就不再呈現。而抽象播放器模式類中定義了一系列的鉤子方法,並提供了默認的實現,用於判斷是否需要創建對應的部件。如果具體播放器模式不需要某個部件,則具體播放器模式覆蓋對應的鉤子方法。
播放模式.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; } //是否建造播放窗口(鉤子方法) virtual bool IsBuildWindow() { return true; } //是否建造播放菜單(鉤子方法) virtual bool IsBuildMenu() { return true; } //是否建造播放列表(鉤子方法) virtual bool IsBuildPlayList() { return true; } //是否建造播放進度條(鉤子方法) virtual bool IsBuildControlBar() { return true; } //是否建造收藏列表(鉤子方法) virtual bool IsBuildCollectList() { return true; } }; //完整播放模式 class FullPattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); //完整播放模式不需要建造收藏列表 bool IsBuildCollectList() { return false; } }; //精簡播放模式 class SimplePattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); //精簡播放模式不需要建造播放菜單 bool IsBuildMenu() { return false; } //精簡播放模式不需要建造播放列表 bool IsBuildPlayList() { return false; } //精簡播放模式不需要建造收藏列表 bool IsBuildCollectList() { return false; } }; //記憶播放模式 class MemoryPattern : public PlayPattern { public: void BuildWindow(); void BuildMenu(); void BuildPlayList(); void BuildControlBar(); void BuildCollectList(); //記憶播放模式不需要建造播放菜單 bool IsBuildMenu() { return false; } //記憶播放模式不需要建造播放列表 bool IsBuildPlayList() { return false; } }; #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("收藏列表"); }
在暴風影音播放器指導者ContructManage中,調用了一系列的鉤子方法,用於判斷在不同播放模式下,是否需要創建對應的部件。暴風影音播放器指揮者類.h頭文件實現如下:
#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() { bool bRetVal = true; //根據需要建造播放窗口 bRetVal = m_pPlayPattern->IsBuildWindow(); if( true == bRetVal ) { m_pPlayPattern->BuildWindow(); } //根據需要建造播放菜單 bRetVal = m_pPlayPattern->IsBuildMenu(); if( true == bRetVal ) { m_pPlayPattern->BuildMenu(); } //根據需要建造播放列表 bRetVal = m_pPlayPattern->IsBuildPlayList(); if( true == bRetVal ) { m_pPlayPattern->BuildPlayList(); } //根據需要建造播放進度條 bRetVal = m_pPlayPattern->IsBuildControlBar(); if( true == bRetVal ) { m_pPlayPattern->BuildControlBar(); } //根據需要建造收藏列表 bRetVal = m_pPlayPattern->IsBuildCollectList(); if( true == bRetVal ) { m_pPlayPattern->BuildCollectList(); } //返回已經建造好的播放器 Player * pPlayer = m_pPlayPattern->GetPlayer(); return pPlayer; }測試程序實現代碼如下:
#include編譯並執行,結果如下:#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; }
通過引入鉤子方法,我們可以在建造者指導者類中對復雜產品的構建進行精細的控制,不僅指定buildPartX()方法的執行順序,還可以控制是否需要執行某個buildPartX()方法。
5、建造者模式總結
建造者模式的核心在於如何一步步構建一個包含多個組成部件的完整對象,使用相同的構建過程構建不同的產品,在軟件開發中,如果我們需要創建復雜對象並希望系統具備很好的靈活性和可擴展性可以考慮使用建造者模式。
1.主要優點
建造者模式的主要優點如下:
(1) 在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。建造者模式封裝了產品具體的創建流程,符合"封裝變化原則"。
(2) 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。由於指揮者類針對抽象建造者編程,增加新的具體建造者無須修改原有類庫的代碼,系統擴展方便,符合“開閉原則”,也符合"針對抽象進行編程而不是針對具體編程原則"。
(3) 可以更加精細地控制產品的創建過程。將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
2.主要缺點
建造者模式的主要缺點如下:
(1) 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,例如很多組成部分都不相同,不適合使用建造者模式,因此其使用范圍受到一定的限制。
(2) 如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,增加系統的理解難度和運行成本。
3.建造者模式的具體應用
(1)在游戲角色中,存在魔鬼、天使、英雄等角色。這些角色都包含相同的建造過程(建造頭、腳、外觀等),而每一個游戲角色建造方法各不相同。
(2)解析XML格式的配置文件時,需要解析配置文件的頭部信息、數據體、尾部信息等。可以把解析的三個過程視為建造的三個過程。
(3)解析Rtf文檔格式同樣存在和解析XML格式的配置文件相同的情況。
(4)我們使用Email發送郵件的是否,需要填寫郵件標題、收件人、郵件內容等信息。可以把填寫郵件標題、收件人、郵件內容視為三個建造過程。
(5)我們在定義Socket網絡通信協議的時候,需要定義數據祯,每祯由包頭、包體、包尾組成。這樣在通信的雙方,就可以按照同樣的格式進行收發信息。