版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t60339/article/details/82769528
简介
插件是基于开发人员预先定义好的标准接口开发的独立部件,windows平台下多以dll形式呈现
有的公司在软件开发中,并不会做软件设计,更没有相关文档,纯粹想到哪写到哪,当软件完工进入维护/功能扩展阶段后,如果因为某种原因,新的人员进入软件改进。那么恭喜,新人员扩展功能非常困难,还得承担相当的破坏现有功能的风险
使用插件系统可以一定程度上解决上述问题,当系统需要的功能不变,仅需变更实现方式的时候,插件系统表现出色,使用插件的好处很多,这里主要说以下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;
}