插件系統

簡介

插件是基於開發人員預先定義好的標準接口開發的獨立部件,windows平臺下多以dll形式呈現

有的公司在軟件開發中,並不會做軟件設計,更沒有相關文檔,純粹想到哪寫到哪,當軟件完工進入維護/功能擴展階段後,如果因爲某種原因,新的人員進入軟件改進。那麼恭喜,新人員擴展功能非常困難,還得承擔相當的破壞現有功能的風險

使用插件系統可以一定程度上解決上述問題,當系統需要的功能不變,僅需變更實現方式的時候,插件系統表現出色,使用插件的好處很多,這裏主要說以下2點:

  1. 擴展性強。標準接口的新的實現,只需要做一個插件
  2. 更新量小。功能的更新只需要更新插件,避免了重新發布整個應用程序

使用插件應特別注意:插件API接口應保持長期不變,如果API接口需要不斷變更,不能使用插件系統來開發應用程序

代碼示例

下面用c++代碼描述一個最簡單的插件系統

插件管理器

插件管理器負責插件的安裝,註銷,插件對象的獲取,一般使用線程安全的單例模式實現

class CPluginManager
{
public:
    static CPluginManager* GetInstance();

    bool Install(wstring name);
    void Uninstall(wstring name);
    void Uninstall();
    CPlugin* GetPlugin(wstring name);
    void SetPluginPath(wstring sPluginPath);
    wstring GetPluginPath();

private:
    CPluginManager();
    ~CPluginManager();
    map<wstring, HINSTANCE> m_mapPlugs;

    wstring m_sPluginPath;
    static CPluginManager* pInstance;
};

安裝插件

bool CPluginManager::Install(wstring name)
{
    if (m_mapPlugs.find(name) != m_mapPlugs.end())
    {
        return true;
    }

    wstring path = m_sPluginPath + name;
    HINSTANCE instance = LoadLibraryW(path.c_str());
    if (instance)
    {
        m_mapPlugs[name] = instance;
        return true;
    }

    return false;
}

註銷插件

void CPluginManager::Uninstall(wstring name)
{
    if (m_mapPlugs.find(name) == m_mapPlugs.end())
    {
        return ;
    }

    for (auto it = m_mapPlugs.begin(); it != m_mapPlugs.end();)
    {
        if (it->first == name)
        {
            FreeLibrary(it->second);
            it = m_mapPlugs.erase(it);
        }
        else
        {
            it++;
        }
    }

    return ;
}

獲取插件對象

CPlugin* CPluginManager::GetPlugin(wstring name)
{
    if (m_mapPlugs.find(name) == m_mapPlugs.end())
    {
        return nullptr;
    }

    Fn f = (Fn)GetProcAddress(m_mapPlugs[name], "?GetInstance@@YAPAVCPlugin@@XZ");
    if (f)
    {
        return f();
    }

    return nullptr;
}

抽象插件類

此類定義插件支持的所有功能

class CPlugin
{
public:
    virtual ~CPlugin() {};
    virtual void Show() = 0;
    virtual void Release() = 0;
};

插件1

class CPlugin1 : public CPlugin
{
public:
    virtual void Show() { MessageBox(NULL, TEXT("this is plugin1"), TEXT("test"), MB_OK); }
    virtual void Release() { delete this; }
};



__declspec(dllexport) CPlugin* GetInstance()
{
    return new CPlugin1;
}

插件2

class CPlugin2 : public CPlugin
{
public:
    virtual void Show() { MessageBox(NULL, TEXT("this is plugin2"), TEXT("test"), MB_OK); }
    virtual void Release() { delete this; }
};



__declspec(dllexport) CPlugin* GetInstance()
{
    return new CPlugin2;
}

簡單測試

    CPluginManager* pm = CPluginManager::GetInstance();
    pm->Install(L"dll1.dll");
    pm->Install(L"dll2.dll");
    CPlugin* p1 =  pm->GetPlugin(L"dll1.dll");
    CPlugin* p2 = pm->GetPlugin(L"dll2.dll");
    p1->Show();
    p2->Show();
    p1->Release();
    p2->Release();
    pm->Uninstall(L"dll1.dll");
    pm->Uninstall(L"dll2.dll");

插件管理器完整實現

#include "PluginManager.h"

typedef CPlugin* (*Fn)();

CPluginManager* CPluginManager::pInstance = new CPluginManager;

CPluginManager::CPluginManager()
{
    m_sPluginPath = L"d:/plugins/";
}


CPluginManager::~CPluginManager()
{
}

CPluginManager* CPluginManager::GetInstance()
{    
    return pInstance;
}

bool CPluginManager::Install(wstring name)
{
    if (m_mapPlugs.find(name) != m_mapPlugs.end())
    {
        return true;
    }

    wstring path = m_sPluginPath + name;
    HINSTANCE instance = LoadLibraryW(path.c_str());
    if (instance)
    {
        m_mapPlugs[name] = instance;
        return true;
    }

    return false;
}

void CPluginManager::Uninstall(wstring name)
{
    if (m_mapPlugs.find(name) == m_mapPlugs.end())
    {
        return ;
    }

    for (auto it = m_mapPlugs.begin(); it != m_mapPlugs.end();)
    {
        if (it->first == name)
        {
            FreeLibrary(it->second);
            it = m_mapPlugs.erase(it);
        }
        else
        {
            it++;
        }
    }

    return ;
}

CPlugin* CPluginManager::GetPlugin(wstring name)
{
    if (m_mapPlugs.find(name) == m_mapPlugs.end())
    {
        return nullptr;
    }

    Fn f = (Fn)GetProcAddress(m_mapPlugs[name], "?GetInstance@@YAPAVCPlugin@@XZ");
    if (f)
    {
        return f();
    }

    return nullptr;
}

void CPluginManager::Uninstall()
{
    for (auto it = m_mapPlugs.begin(); it != m_mapPlugs.end();)
    {
        FreeLibrary(it->second);
        it = m_mapPlugs.erase(it);
    }
    return ;
}

void CPluginManager::SetPluginPath(wstring sPluginPath)
{
    m_sPluginPath = sPluginPath;
}

wstring CPluginManager::GetPluginPath()
{
    return m_sPluginPath;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章