所謂命令控制模式,就是對應的行爲進行封裝,通過命令就能控制,你可以理解爲linux下指令操作。
比如一個操作包括,A1、A2、.....A10這10步操作,如果某一步失敗,那麼就進行倒回,如果這10個操作的業務類型各不相同,並且所需要的參數也不盡相同,操作起來就比較困難,如果我能將他們全部封裝成指令模式,只通過A1到A10這10個字符串就觸發,那麼實現起來就容易的多。
對於網絡編程,命令控制就變得必不可少了,該模型可以幫你將網絡層與業務層完美的管理在一起。
實現約束:
1、每一類業務我需要劃分爲一個業務入口類,便於統一管理。
2、我有很多類的業務,爲了便於擴展,每添加一個業務類,我需要儘量少改動框架內容。
3、我可以將每一個業務入口類的函數定義成一個命令。
4、每一個命令字允許我傳入不同的參數列表
基於上述約束,實現起來可能有點困難,所以在此進行梳理一下,分兩步進行:
第一步:業務入口類的管理實現
實現原理:
1、模板類靜態成員在有調用的情況下,編譯器會自動展開。
2、靜態成員會在main函數之前進行初始化
3、在每一個業務入口類中,定義一個指定靜態函數,在函數中使用模板類,以達到讓編譯器生成模板類實例的目的;
4、模板類的靜態成員初始化爲業務類的靜態函數地址。
5、靜態成員初始化時,讓模板類之間形成一個鏈表
基於以上原理,我們可以實現一個如下圖所示的,父類與子類的關係:
第二步:將所有容器的命令字進行彙總
這裏相對就比較簡單了,直接遍歷容器,執行所有的容器函數,將命令字進行彙總。
代碼實現:
.h文件:
#include <map>
#include <string>
#include <iostream>
#include <unordered_map>
#include <memory>
#include <functional>
#include "singleton.h"
#include "anyval.h"
#define BEGINE_OPCODEREG(className) public:
static void OpcodeInit() {
COPHandleContainer<className> handle;
#define DEFINE_OPCODE(opcode, funcAddr) MakeFuncEntityNode(funcAddr, opcode, #funcAddr);
#define END_OPCODEREG() } private:
//命令字分發類
class COpcodeDispatch
{
public:
~COpcodeDispatch(void) {};
void Initialize();
void RegisterOpcode(const char* opcode, AnyVar opProc, AnyVar funcName);
//命令字分發
template<typename... ARGS>
void Dispatch(const std::string& opcode, ARGS... args)
{
auto iter = m_opHandle.find(opcode);
if (m_opHandle.end() == iter)
{
return ;
}
AnyVar resolver = iter->second;
std::function<void (ARGS...)> funcPtr = any_cast<std::function<void (ARGS...)>>(resolver);
funcPtr(args...);
}
void Dump();
private:
std::unordered_map<std::string, AnyVar> m_opHandle;
std::unordered_map<std::string, AnyVar> m_opFuncName;
};
typedef Singleton<COpcodeDispatch> COpcodeDispatchAgent;
//該類用於存儲所有命令字節點的信息,包括函數地址、函數名稱
template <typename T, typename... ARGS>
class CMemFuncEntityNode
{
public:
typedef void (T::*mem_func_type)(ARGS...);
CMemFuncEntityNode(mem_func_type memFunc, const char* memFuncName) :m_memFuncAddr(memFunc), m_memFuncName(memFuncName) {}
void operator()(ARGS...args)
{
T obj;
(obj.*m_memFuncAddr)(args...);
}
//支持Opcode的類,原生支持動態創建
void* DynCreate()
{
return new T;
}
const char* GetMemFuncName()
{
return m_memFuncName[0] == '&' ? m_memFuncName + 1 : m_memFuncName;
}
private:
mem_func_type m_memFuncAddr;
const char* m_memFuncName;
};
template<typename T, typename... ARGS>
void MakeFuncEntityNode(void (T::*mem_func_type)(ARGS...), const char* opcode, const char* memFuncName)
{
auto opNode = std::make_shared<CMemFuncEntityNode<T, ARGS...>>(mem_func_type, memFuncName);
//統一轉化成 void (ARGS...) 函數,用anyval包裝
std::function<void (ARGS...)> function = [opNode](ARGS... args) {
(*opNode)(args...);
};
std::function<const char* ()> funcName = [opNode]() {
return opNode->GetMemFuncName();
};
COpcodeDispatchAgent::get_instance().RegisterOpcode(opcode, function, funcName);
}
//容器基類,存儲所有節點信息及容器節點信息
class COPContainerBase
{
public:
static void Initialize();
protected:
typedef void(*cont_func_type)();
virtual ~COPContainerBase();
//存儲容器節點,返回容器頭節點
static COPContainerBase*& Head();
//此函數爲虛函數,目的是爲了讓編譯器對繼承該類並實現該函數的類進行檢查
virtual void DoNothing()const;
protected:
cont_func_type m_containtFunc;
COPContainerBase* m_nextContainer;
};
//容器類
template <typename T>
class COPHandleContainer : public COPContainerBase
{
public:
COPHandleContainer(void)
{
}
static COPHandleContainer* GetInstance()
{
//注:此處爲單例,如果多次調用,Head()鏈表將會進入形成循環
static COPHandleContainer<T> containerIns;
return &containerIns;
}
//該函數爲虛函數,編譯器會進行檢查,從而實現對靜態變量引用的目的
//所有實例化該模板類的類,都會初始化該靜態變量,所以必須實現T::OpcodeInit靜態函數
inline void DoNothing()const
{
m_opInstance.DoNothing();
}
private:
struct ContaintInstance
{
ContaintInstance(cont_func_type containtFunc)
{
#ifdef _DEBUG
std::cout << "初始化容器函數" << std::endl;
#endif
COPHandleContainer *container = COPHandleContainer::GetInstance();
container->m_containtFunc = containtFunc;
container->m_nextContainer = Head();
Head() = container;
}
inline void DoNothing()const {}
};
static ContaintInstance m_opInstance;
};
//opcode容器加載
template < typename T >
typename COPHandleContainer<T>::ContaintInstance COPHandleContainer<T>::m_opInstance(T::OpcodeInit);
.cpp文件
#include "opcodedispatch.h"
void COpcodeDispatch::RegisterOpcode(const char* opcode, AnyVar opProc, AnyVar funcName)
{
if (m_opHandle.end() != m_opHandle.find(opcode))
{
throw std::invalid_argument(std::string(opcode) + " : this opcode has already exist!");
}
else
{
m_opHandle.emplace(opcode, opProc);
m_opFuncName.emplace(opcode, funcName);
}
}
void COpcodeDispatch::Initialize()
{
COPContainerBase::Initialize();
}
void COpcodeDispatch::Dump()
{
for(auto item : m_opFuncName)
{
AnyVar resolver = item.second;
std::function<const char* ()> funcPtr = any_cast<std::function<const char* ()>>(resolver);
std::cout << item.first << "-->" << funcPtr() << std::endl;;
}
}
/*********************************************************
COPContainerBase
***********************************************************/
COPContainerBase::~COPContainerBase()
{
}
//存儲容器節點,返回容器頭節點
COPContainerBase*& COPContainerBase::Head()
{
static COPContainerBase *containerHead = 0;
return containerHead;
}
void COPContainerBase::Initialize()
{
//初始化容器
COPContainerBase* currContainer = Head();
while (currContainer != NULL)
{
(*currContainer->m_containtFunc)();
currContainer = currContainer->m_nextContainer;
}
}
//此函數爲虛函數,目的是爲了讓編譯器對繼承該類並實現該函數的類進行檢查
void COPContainerBase::DoNothing()const
{
}
測試代碼:
class TestOpcode
{
BEGINE_OPCODEREG(TestOpcode)
DEFINE_OPCODE("TestFunc", &TestOpcode::Func)
DEFINE_OPCODE("TestFunc2", &TestOpcode::Func2)
END_OPCODEREG()
public:
void Func()
{
std::cout << "TestOpcode Func" << std::endl;
}
void Func2(int a, int b)
{
std::cout << "TestOpcode func2:" << a*b << std::endl;
}
};
int main()
{
COpcodeDispatchAgent::get_instance().Initialize();
COpcodeDispatchAgent::get_instance().Dump();
COpcodeDispatchAgent::get_instance().Dispatch("TestFunc");
COpcodeDispatchAgent::get_instance().Dispatch("TestFunc2", 10, 20);
return 0;
}
輸出:
TestFunc2-->TestOpcode::Func2
TestFunc-->TestOpcode::Func
TestOpcode Func
TestOpcode func2:200