亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

設計模式介紹之六:工廠模式(factory)的巧妙

系統 1535 0

本文展示了實際項目中使用到的一個工廠模式實現,在向系統中添加新類型時,只需要在新類型的實現文件這一處做改動,將新增類型對應用程序代碼的干擾降到了最低。

這個工廠實現的基本思想是:繼承自同一個接口的新類型,通過一個函數來創建其對象,利用C++ 中類的構造函數會被自動調用這一特性,在新類型的實現文件中定義一個靜態的(輔助)類對象,在該輔助類的構造函數中,向工廠單例注冊新類型的創建函數。

先看下代碼,然后我們一一來解釋。下面是命令接口 CommandObject 的頭文件內容:

    class CommandObject
{
public:
    CommandObject(){}
    virtual ~CommandObject(){}

    virtual void execute() = 0;
};
  

CommandObject 是一個純虛類,作為公共的接口。

我在正式的系統中使用命令模式,封裝特定的操作,傳遞命令對象給一些 UI 元素,如 button 等,在 UI 元素被鼠標或按鍵觸發時,會調用關聯的 CommandObject 來執行特定的命令。有關命令模式,參考文章《 設計模式介紹之三:命令模式(command) 》。

下面是命令對象工廠類的頭文件:

    #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

  

在這個頭文件中,定義了 CommandObjectFactory 這個工廠類。首先它是一個單例( singleton ),這是通常的做法,工廠類作為單例實現。關于單例,請參考文章《 設計模式介紹之二:單例模式(Singleton) 》。

CommandObjectFactory 定義了用于創建對象的工廠方法 commandObject ,它接受一個字符串作為關鍵字,內部根據這個關鍵字來創建命令對象。還定義了一個方法 regist ,用來向工廠內注冊命令對象的創建函數,主要是被后面定義的輔助宏EXPORT_COMMAND_CREATOR 使用,自動進行創建函數的注冊。

宏EXPORT_COMMAND_CREATOR 有兩個參數,一個是與具體命令對象實現類一一對應的關鍵字 KEYWORD,一個是命令對象類類名 COMMANDCLASS 。這個宏非常關鍵,正是它幫助我們完成創建函數的注冊,同時使得我們把新增類型的代碼改動限制在新類型的實現文件中,對已有代碼沒有任何影響。

宏EXPORT_COMMAND_CREATOR展開后又分為幾部分:輔助類聲明、作用域為文件的全局靜態輔助類實例、輔助類構造函數調用 CommandObjectFactory::regist() 注冊創建函數。它的使用也非常簡單,我們會在后面提到。

下面是 CommandObjectFactory 的實現:

    #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;
}

  

實現比較簡單,我們在 CommandObjectFactory 內部維護了兩個數組,分別存貯關鍵字和命令對象創建函數,兩者一一對應, regist() 函數維護創建函數的注冊和內部數組的動態增長。 commandObject() 函數則根據傳入的關鍵字 szKeyword ,在內部的數組中做字符串比較,關鍵字匹配后定位對應的創建函數來創建命令對象。

下面看看具體命令對象類的實現和自動注冊宏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);

  

一切都很直觀,不必多說了。

下面是 main() 函數,看看怎么使用命令對象工廠來創建想要的命令對象:

    int main()
{
    CommandObject * cmd = CommandObjectFactory::instance()->commandObject("shutdown");
    cmd->execute();
    return 0;
}
  

非常簡單,不必要解釋了。下面是程序執行的結果:

設計模式介紹之六:工廠模式(factory)的巧妙實現

好啦,到現在為止,一個簡單好用的簡單工廠模式實現介紹完畢,我特意做了簡化,以便能更好的理解實現的思路,在實際的項目中,稍微復雜了一些。

回顧:


設計模式介紹之六:工廠模式(factory)的巧妙實現


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产一区二区三区高清 | 精品无人区乱码1区2区 | 欧美天天综合 | 一区二区三区欧美日韩国产 | 奇米影视狠狠狠天天777 | 久久精品国产精品亚洲20 | 青青草a| 在线欧美精品一区二区三区 | 日韩伦理亚洲欧美在线一区 | 第四色激情网 | 一级片视频免费看 | 久久99精品国产免费观看 | 久久久国产乱子伦精品 | 久久福利一区二区三区 | 欧美韩国日本在线观看 | 久久性精品 | 综合亚洲一区二区三区 | 国产真实乱子伦精品 | 国产乱人免费视频 | 国产成人精品亚洲日本在线 | 国产一区二区三区四区 | 日韩欧美在线一级一中文字暮 | 国内精品久久久久久中文字幕 | 午夜私人影院粉色视频我要 | 亚洲视频2 | 女孕学护士一级毛片 | 久久久国产乱子伦精品 | 国产精品久久久久这里只有精品 | 奇米影视777中文久久爱 | 日韩欧美网址 | 夜夜操影院 | 四虎永久在线 | 一本色道久久88加勒比—综合 | 国产欧洲亚洲 | 天天做天天爱夜夜想毛片 | 中文字幕在线免费播放 | 日本一级特黄aa大片24免费 | 精品国产免费福利片 | 亚洲精品69 | 色鬼久久爱综合久久鬼色 | 国产欧美一区二区三区视频 |