本文展示了實(shí)際項(xiàng)目中使用到的一個(gè)工廠模式實(shí)現(xiàn),在向系統(tǒng)中添加新類(lèi)型時(shí),只需要在新類(lèi)型的實(shí)現(xiàn)文件這一處做改動(dòng),將新增類(lèi)型對(duì)應(yīng)用程序代碼的干擾降到了最低。
這個(gè)工廠實(shí)現(xiàn)的基本思想是:繼承自同一個(gè)接口的新類(lèi)型,通過(guò)一個(gè)函數(shù)來(lái)創(chuàng)建其對(duì)象,利用C++ 中類(lèi)的構(gòu)造函數(shù)會(huì)被自動(dòng)調(diào)用這一特性,在新類(lèi)型的實(shí)現(xiàn)文件中定義一個(gè)靜態(tài)的(輔助)類(lèi)對(duì)象,在該輔助類(lèi)的構(gòu)造函數(shù)中,向工廠單例注冊(cè)新類(lèi)型的創(chuàng)建函數(shù)。
先看下代碼,然后我們一一來(lái)解釋。下面是命令接口 CommandObject 的頭文件內(nèi)容:
class CommandObject { public: CommandObject(){} virtual ~CommandObject(){} virtual void execute() = 0; };
CommandObject 是一個(gè)純虛類(lèi),作為公共的接口。
我在正式的系統(tǒng)中使用命令模式,封裝特定的操作,傳遞命令對(duì)象給一些 UI 元素,如 button 等,在 UI 元素被鼠標(biāo)或按鍵觸發(fā)時(shí),會(huì)調(diào)用關(guān)聯(lián)的 CommandObject 來(lái)執(zhí)行特定的命令。有關(guān)命令模式,參考文章《 設(shè)計(jì)模式介紹之三:命令模式(command) 》。
下面是命令對(duì)象工廠類(lèi)的頭文件:
#ifndef COMMANDOBJECTFACTORY_H #define COMMANDOBJECTFACTORY_H #include "commandObject.h" typedef CommandObject * (*LPFNCREATE)(); class CommandObjectFactory { CommandObjectFactory(const CommandObjectFactory &); CommandObjectFactory & operator=(const CommandObjectFactory &); CommandObjectFactory(); public: ~CommandObjectFactory(); static CommandObjectFactory * instance(); CommandObject * commandObject(const char * szKeyword); void regist(const char * szKeyword, LPFNCREATE lpfnCreate); private: const char ** m_keywords; LPFNCREATE * m_functions; int m_iCount; int m_iCursor; }; #define EXPORT_COMMAND_CREATOR(KEYWORD, COMMANDCLASS) \ CommandObject * _command_object_creator_##KEYWORD() {\ return new COMMANDCLASS;\ }\ class Static##KEYWORD##PluginInstance{ \ public: \ Static##KEYWORD##PluginInstance(){ \ CommandObjectFactory::instance()->regist(#KEYWORD, _command_object_creator_##KEYWORD);\ }\ };\ static Static##KEYWORD##PluginInstance static##KEYWORD##Instance #endif // COMMANDOBJECTFACTORY_H
在這個(gè)頭文件中,定義了 CommandObjectFactory 這個(gè)工廠類(lèi)。首先它是一個(gè)單例( singleton ),這是通常的做法,工廠類(lèi)作為單例實(shí)現(xiàn)。關(guān)于單例,請(qǐng)參考文章《 設(shè)計(jì)模式介紹之二:?jiǎn)卫J?Singleton) 》。
CommandObjectFactory 定義了用于創(chuàng)建對(duì)象的工廠方法 commandObject ,它接受一個(gè)字符串作為關(guān)鍵字,內(nèi)部根據(jù)這個(gè)關(guān)鍵字來(lái)創(chuàng)建命令對(duì)象。還定義了一個(gè)方法 regist ,用來(lái)向工廠內(nèi)注冊(cè)命令對(duì)象的創(chuàng)建函數(shù),主要是被后面定義的輔助宏EXPORT_COMMAND_CREATOR 使用,自動(dòng)進(jìn)行創(chuàng)建函數(shù)的注冊(cè)。
宏EXPORT_COMMAND_CREATOR 有兩個(gè)參數(shù),一個(gè)是與具體命令對(duì)象實(shí)現(xiàn)類(lèi)一一對(duì)應(yīng)的關(guān)鍵字 KEYWORD,一個(gè)是命令對(duì)象類(lèi)類(lèi)名 COMMANDCLASS 。這個(gè)宏非常關(guān)鍵,正是它幫助我們完成創(chuàng)建函數(shù)的注冊(cè),同時(shí)使得我們把新增類(lèi)型的代碼改動(dòng)限制在新類(lèi)型的實(shí)現(xiàn)文件中,對(duì)已有代碼沒(méi)有任何影響。
宏EXPORT_COMMAND_CREATOR展開(kāi)后又分為幾部分:輔助類(lèi)聲明、作用域?yàn)槲募娜朱o態(tài)輔助類(lèi)實(shí)例、輔助類(lèi)構(gòu)造函數(shù)調(diào)用 CommandObjectFactory::regist() 注冊(cè)創(chuàng)建函數(shù)。它的使用也非常簡(jiǎn)單,我們會(huì)在后面提到。
下面是 CommandObjectFactory 的實(shí)現(xiàn):
#include "commandObjectFactory.h" #include <iostream> #include <string.h> #include <malloc.h> using namespace std; #define INITIALISE_SIZE 32 #define INCREMENT_SIZE 8 static CommandObjectFactory * s_instance = 0; CommandObjectFactory::CommandObjectFactory() : m_keywords(0) , m_functions(0) , m_iCount(0) , m_iCursor(0) { } CommandObjectFactory::~CommandObjectFactory() { } CommandObjectFactory * CommandObjectFactory::instance() { if(!s_instance) { s_instance = new CommandObjectFactory; cout << "CommandObjectFactory initialised" << endl; } return s_instance; } void CommandObjectFactory::regist(const char * szKeyword, LPFNCREATE lpfnCreate) { if(!szKeyword || !lpfnCreate) return; //repeat check for(int i = 0; i < m_iCursor; ++i) { if(!strcmp(m_keywords[i], szKeyword)) return ; } if(!m_functions) { m_functions = (LPFNCREATE*)calloc(INITIALISE_SIZE, sizeof(LPFNCREATE)); m_keywords = (const char**)calloc(INITIALISE_SIZE, sizeof(char*)); m_iCount = INITIALISE_SIZE; m_iCursor = 0; } else if( m_iCursor == m_iCount ) { m_iCount += INCREMENT_SIZE; m_functions = (LPFNCREATE*)realloc( m_functions, m_iCount * sizeof(LPFNCREATE) ); m_keywords = (const char**)realloc( m_keywords, m_iCount * sizeof(char*)); } m_keywords[m_iCursor] = (const char *)strdup(szKeyword); m_functions[m_iCursor] = lpfnCreate; m_iCursor++; cout << "register create function for - " << szKeyword << endl; } CommandObject * CommandObjectFactory::commandObject(const char * szKeyword) { for(int i = 0; i < m_iCursor; ++i) { if(!strcmp(m_keywords[i], szKeyword)) { return m_functions[i](); } } cout << "no create function for - " << szKeyword << endl; return 0; }
實(shí)現(xiàn)比較簡(jiǎn)單,我們?cè)?CommandObjectFactory 內(nèi)部維護(hù)了兩個(gè)數(shù)組,分別存貯關(guān)鍵字和命令對(duì)象創(chuàng)建函數(shù),兩者一一對(duì)應(yīng), regist() 函數(shù)維護(hù)創(chuàng)建函數(shù)的注冊(cè)和內(nèi)部數(shù)組的動(dòng)態(tài)增長(zhǎng)。 commandObject() 函數(shù)則根據(jù)傳入的關(guān)鍵字 szKeyword ,在內(nèi)部的數(shù)組中做字符串比較,關(guān)鍵字匹配后定位對(duì)應(yīng)的創(chuàng)建函數(shù)來(lái)創(chuàng)建命令對(duì)象。
下面看看具體命令對(duì)象類(lèi)的實(shí)現(xiàn)和自動(dòng)注冊(cè)宏EXPORT_COMMAND_CREATOR 的使用。代碼:
class ShutdownCommand : public CommandObject { public: void execute() { cout << endl << "ShutdownCommand::execute" << endl; } }; EXPORT_COMMAND_CREATOR(shutdown, ShutdownCommand); class RebootCommand : public CommandObject { public: void execute() { cout << endl << "RebootCommand::execute" << endl; } }; EXPORT_COMMAND_CREATOR(reboot, RebootCommand);
一切都很直觀,不必多說(shuō)了。
下面是 main() 函數(shù),看看怎么使用命令對(duì)象工廠來(lái)創(chuàng)建想要的命令對(duì)象:
int main() { CommandObject * cmd = CommandObjectFactory::instance()->commandObject("shutdown"); cmd->execute(); return 0; }
非常簡(jiǎn)單,不必要解釋了。下面是程序執(zhí)行的結(jié)果:
好啦,到現(xiàn)在為止,一個(gè)簡(jiǎn)單好用的簡(jiǎn)單工廠模式實(shí)現(xiàn)介紹完畢,我特意做了簡(jiǎn)化,以便能更好的理解實(shí)現(xiàn)的思路,在實(shí)際的項(xiàng)目中,稍微復(fù)雜了一些。
回顧:
- 設(shè)計(jì)模式介紹之一:開(kāi)篇概述
- 設(shè)計(jì)模式介紹之二:?jiǎn)卫J?Singleton)
- 設(shè)計(jì)模式介紹之三:命令模式(command)
- 設(shè)計(jì)模式介紹之四:模板方法(Template Method)模式
-
設(shè)計(jì)模式介紹之五:工廠模式(factory)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
