C++ 九陰真經之命令控制模式

 所謂命令控制模式,就是對應的行爲進行封裝,通過命令就能控制,你可以理解爲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

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