插件系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t60339/article/details/82769528

简介

插件是基于开发人员预先定义好的标准接口开发的独立部件,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;
}

猜你喜欢

转载自blog.csdn.net/t60339/article/details/82769528