一种基于总线思想的软件框架
项目上学到的,直接上实例代码,使用总线类来实现模块之间通信
/// Invoker抽象类
class IComInvoker
{
public:
virtual ~IComInvoker(){};
//! 调用接口,可以使用boost::any代替QVariant
virtual QVariant Invoke(QVariant args[], int nArgNum) = 0;
//! 判断目标参数类型是否合法
virtual bool CheckMethodValid(QVariant args[], int nArgNum) = 0;
}
类成员指针声明形式:typedef bool (ClassA::*Method)(int)
赋值: Method method = &ClassA::Func;
调用方式: pA->*method(1)
///! 调用器具体类,这里只演示一个形参的Invoker1,实际项目中会构造多个形参的Invoker2、Invoker3...
template<class R, class ObjT, class T1>
class Invoker1: public IComInvoker
{
typedef R (ObjT::*Method)(T1);
private:
ObjT* m_obj;
Mehtod m_memFunc;
public:
Invoker1(ObjT* obj, Method method):m_obj(obj),m_memFunc(method){}
QVariant Invoke(QVariant args[], int nArgNum)
{
if(nArgNum != 1)
return R();
QVariant v0 = args[0];
return (m_obj->*m_memFunc)(v0.value<T1>());
}
bool CheckMethodValid(QVariant args[], int nArgNum)
{
//校验参数是否为目标类型,略
}
}
///! 总线类,实际项目中做成单例,维护一个总线
class SvrBus
{
typedef QMap<QString, QMap<QString, IComInvoker*>> ComMethods;
public:
IComInvoker* GetInvoker(QString strModule, QString strInvokerName)
{
return m_mapMethods[strModule][strInvokerName];
}
void RegisterMethod(QString strModule, QString strMethodName, IComInvoker* invoker)
{
//多个模块注册时考虑加锁保证线程安全
m_mapMethods[strModule][strMethodName] = invoker;
}
private:
ComMethods m_mapMethods;
}
///! 需要注册到总线的模块
class Module1
{
public:
Module1(SvrBus& svrBus)
{
//! 此处可以进一步做成宏来简化每个模块的动作
IComInvoker* invoker = (IComInvoker*)new Invoker1<void, Module1, int>(this, &Module1::Func)
svrBus.RegisterMethod("Module1", "Func", invoker);
}
private:
void Func(int m);
}
///!外部调用该模块示例(该处可进一步封装为SvrWrap类)
IComInvoker* invoker = svrBus.GetInvoker("Module1", "Func");
QVariant args[1];
args[0] = 888;
if(invoker->CheckMethodValid(args, 1))
{
invoker->Invoke(args, 1);
}
通过这种框架,两个独立模块之间仅依赖SvrBus进行通信,可以做到尽可能解耦,在调用时进行类型检查等安全措施,不会因为兼容问题造成闪退。