最近闲着没事, 整理原来代码时候发现用函数对象加上模版实现责任链模式的方法很值得温习, 重新理了一下, 整个过程如下:
测试结果:
[jackhuang@bogon chain]$ ./test
[main.cc:main:79] INFO: Test begin!
[chain.cc:registerNewHandler:18] INFO: handler = TestClass1 successfully added, register handler ok!
[chain.h:addCommand:145] INFO: command = show-status sucessfully added to handler = TestClass1!
[chain.cc:registerNewHandler:18] INFO: handler = TestClass2 successfully added, register handler ok!
[chain.h:addCommand:145] INFO: command = add-status sucessfully added to handler = TestClass2!
[main.cc:testFunc:34] INFO: param is runtime, argc is 100!
[main.cc:testFunc:69] INFO: param is runtime, argc is 101!
[chain.h:removeCommand:238] INFO: command = show-status successfully removed!
[chain.cc:removeHandler:47] INFO: removeing command handler = TestClass1!
[chain.h:removeCommand:238] INFO: command = add-status successfully removed!
[chain.cc:removeHandler:47] INFO: removeing command handler = TestClass2!
[main.cc:main:95] INFO: Test end!
[chain.cc:removeHandler:29] ERROR: handler = TestClass2 not exits, remove handler failed!
[chain.cc:removeHandler:29] ERROR: handler = TestClass1 not exits, remove handler failed!
[jackhuang@bogon chain]$
// chain.h
#ifndef __CHAIN_H__
#define __CHAIN_H__
#include <map>
#include <list>
#include <string>
#include "common.h"
class ACommandHandler
{
public:
explicit ACommandHandler(const std::string & handlerName)
: m_handlerName(handlerName), m_successor(NULL) {}
virtual ~ACommandHandler(){}
void setSuccessor(ACommandHandler *handler)
{
m_successor = handler;
}
ACommandHandler * getSuccessor() const
{
return m_successor;
}
std::string getHandlerName() const
{
return m_handlerName;
}
virtual void handleCommand(const std::string & commandName, std::string & param, int argc) = 0;
protected:
bool haveSuccessor() const
{
return m_successor != NULL ? true : false;
}
std::string m_handlerName;
private:
ACommandHandler *m_successor;
};
template <typename C, typename F> class CommandSet;
template <typename C, typename F>
class CommandHandler : public ACommandHandler
{
public:
CommandHandler(const std::string & handlerName) : ACommandHandler(handlerName) {}
~CommandHandler(){}
bool addCommand(const std::string & commandName, const std::string & helpStr, C & obj, F func);
bool removeCommand(const std::string & commandName);
void handleCommand(const std::string & commandName, std::string & param, int argc);
private:
bool canHandleCommand(const std::string & commandName);
typedef CommandSet<C, F> CommandLookup;
CommandLookup m_commandLookup;
};
template <typename C, typename F>
class CommandDescriptor
{
public:
explicit CommandDescriptor(const std::string & helpStr, C & obj, F func)
: m_helpStr(helpStr), m_obj(obj), m_func(func)
{
}
void executeCommand(std::string & param, int argc)
{
(m_obj.*m_func) (param, argc);
}
private:
CommandDescriptor(const CommandDescriptor &);
CommandDescriptor & operator=(const CommandDescriptor &);
std::string m_helpStr;
C & m_obj;
F m_func;
};
template <typename C, typename F>
class CommandSet
{
public:
CommandSet();
~CommandSet();
typedef CommandDescriptor<C, F> CommandDescriptorType;
bool addCommand(const std::string & commandName, CommandDescriptorType * command);
bool removeCommand(const std::string & commandName);
CommandDescriptorType * findCommand(const std::string & commandName);
void executeCommand(const std::string & commandName, std::string & param, int argc);
private:
typedef std::map<std::string, CommandDescriptorType *> CommandMap;
CommandMap m_commandMap;
};
class CommandServer
{
public:
bool registerNewHandler(ACommandHandler * command);
bool removeHandler(const std::string & handlerName);
ACommandHandler * findHandler(const std::string & handlerName);
void handleCommand(const std::string & commandName, std::string & param, int argc);
static CommandServer * instance();
private:
CommandServer() {}
CommandServer(const CommandServer &);
CommandServer & operator=(const CommandServer &);
typedef std::list<ACommandHandler *> CommandHandlerChain;
CommandHandlerChain m_handlerChain;
static CommandServer * m_instance;
};
// CommandHandler
template <typename C, typename F>
bool CommandHandler<C, F>::addCommand(const std::string & commandName,
const std::string & helpStr,
C & obj, F func)
{
typename CommandSet<C, F>::CommandDescriptorType *command = NULL;
command = new typename CommandSet<C, F>::CommandDescriptorType(helpStr, obj, func);
if (command == NULL)
{
ERR_LOG("no memory, exiting!/n");
exit(-1);
}
bool bRet = m_commandLookup.addCommand(commandName, command);
if (bRet)
{
INFO_LOG("command = %s sucessfully added to handler = %s!/n",
commandName.c_str(), m_handlerName.c_str());
}
return bRet;
}
template <typename C, typename F>
bool CommandHandler<C, F>::removeCommand(const std::string & commandName)
{
return m_commandLookup.removeCommand(commandName);
}
template <typename C, typename F>
void CommandHandler<C, F>::handleCommand(const std::string & commandName,
std::string & param, int argc)
{
if (canHandleCommand(commandName))
{
m_commandLookup.executeCommand(commandName, param, argc);
}
else if (haveSuccessor()) // 传给下一个handler
{
getSuccessor()->handleCommand(commandName, param, argc);
}
}
template <typename C, typename F>
bool CommandHandler<C, F>::canHandleCommand(const std::string & commandName)
{
return (m_commandLookup.findCommand(commandName) != NULL ? true : false);
}
// CommandSet
template <typename C, typename F>
CommandSet<C, F>::CommandSet()
{
}
template <typename C, typename F>
CommandSet<C, F>::~CommandSet()
{
typename CommandMap::iterator itr = m_commandMap.begin();
for (; itr != m_commandMap.end(); ++itr)
{
delete(itr->second);
m_commandMap.erase(itr);
}
m_commandMap.clear();
}
template <typename C, typename F>
bool CommandSet<C, F>::addCommand(const std::string & commandName, CommandDescriptorType * command)
{
if (findCommand(commandName) != NULL)
{
ERR_LOG("command = %s already exists, add command failed!/n", commandName.c_str());
return false;
}
std::pair<typename CommandMap::iterator, bool> inRst;
inRst = m_commandMap.insert(std::make_pair(commandName, command));
if (!inRst.second)
{
ERR_LOG("insert command = %s failed!/n", commandName.c_str());
return false;
}
return true;
}
template <typename C, typename F>
bool CommandSet<C, F>::removeCommand(const std::string & commandName)
{
if (findCommand(commandName) == NULL)
{
ERR_LOG("remove handler failed, command = %s not exist!", commandName.c_str());
return false;
}
typename CommandMap::iterator itr = m_commandMap.begin();
for (; itr != m_commandMap.end(); ++itr)
{
if (commandName == itr->first)
{
delete(itr->second);
m_commandMap.erase(itr);
}
}
INFO_LOG("command = %s successfully removed!/n", commandName.c_str());
return true;
}
template <typename C, typename F>
typename CommandSet<C, F>::CommandDescriptorType * CommandSet<C, F>::findCommand(const std::string & commandName)
{
typename CommandMap::iterator itr = m_commandMap.begin();
for (; itr != m_commandMap.end(); ++itr)
{
if (commandName == itr->first)
{
return itr->second;
}
}
return NULL;
}
template <typename C, typename F>
void CommandSet<C, F>::executeCommand(const std::string & commandName,
std::string & param, int argc)
{
typename CommandSet<C,F>::CommandDescriptorType * command = findCommand(commandName);
if (command == NULL)
{
ERR_LOG("execute command failed, command = %s not exist!/n", commandName.c_str());
return;
}
command->executeCommand(param, argc);
}
#define commandServer_s CommandServer::instance()
#endif
// chain.cc
#include "chain.h"
using namespace std;
bool CommandServer::registerNewHandler(ACommandHandler * handler)
{
if (handler == NULL || findHandler(handler->getHandlerName()) != NULL)
{
ERR_LOG("handler = %s already exists, register handler failed!/n", (handler->getHandlerName()).c_str());
return false;
}
if (!m_handlerChain.empty())
{
(m_handlerChain.back())->setSuccessor(handler);
}
INFO_LOG("handler = %s successfully added, register handler ok!/n", (handler->getHandlerName()).c_str());
m_handlerChain.push_back(handler);
return true;
}
bool CommandServer::removeHandler(const string & handlerName)
{
if (findHandler(handlerName) == NULL)
{
ERR_LOG("handler = %s not exits, remove handler failed!/n", handlerName.c_str());
return false;
}
CommandHandlerChain::iterator cur = m_handlerChain.begin();
CommandHandlerChain::iterator end = m_handlerChain.end();
CommandHandlerChain::iterator prev = m_handlerChain.begin();
while (cur != end)
{
if (handlerName == (*cur)->getHandlerName())
{
// is head
if (prev != cur)
{
(*prev)->setSuccessor((*cur)->getSuccessor());
}
INFO_LOG("removeing command handler = %s!/n", (*cur)->getHandlerName().c_str());
m_handlerChain.erase(cur);
return true;
}
prev = cur;
cur++;
}
return false;
}
ACommandHandler * CommandServer::findHandler(const string & handlerName)
{
CommandHandlerChain::const_iterator cur = m_handlerChain.begin();
CommandHandlerChain::const_iterator end = m_handlerChain.end();
while (cur != end)
{
if (handlerName == (*cur)->getHandlerName())
{
return *cur;
}
cur++;
}
return NULL;
}
CommandServer * CommandServer::m_instance = NULL;
CommandServer * CommandServer::instance()
{
if (m_instance == NULL)
{
m_instance = new CommandServer;
if (m_instance == NULL)
{
ERR_LOG("no memory, exiting!/n");
exit(-1);
}
}
return m_instance;
}
void CommandServer::handleCommand(const string & commandName, std::string & param, int argc)
{
if (m_handlerChain.empty())
{
ERR_LOG("the command chain is empty!/n");
return;
}
(m_handlerChain.front())->handleCommand(commandName, param, argc); // 直接把命令发下去, 让合适的handler处理
}
// common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#define ERR_LOG(format, args...) /
printf("[%s:%s:%d] ERROR: " format, __FILE__, __func__, __LINE__, ##args)
#define INFO_LOG(format, args...) /
printf("[%s:%s:%d] INFO: " format, __FILE__, __func__, __LINE__, ##args);
#endif
//main.cc
#include "chain.h"
#include "common.h"
#include <string>
using namespace std;
class TestClass1
{
public:
TestClass1()
: m_commandHandler("TestClass1")
{
}
~TestClass1()
{
commandServer_s->removeHandler(m_commandHandler.getHandlerName());
}
void registerCommandHandler()
{
commandServer_s->registerNewHandler(&m_commandHandler);
m_commandHandler.addCommand("show-status", "just for test", *this, &TestClass1::testFunc);
}
void deRegisterCommandHandler()
{
m_commandHandler.removeCommand("show-status");
commandServer_s->removeHandler(m_commandHandler.getHandlerName());
}
void testFunc(string & param, int argc)
{
INFO_LOG("param is %s, argc is %d!/n", param.c_str(), argc);
}
private:
typedef void (TestClass1::*FUNC) (string & param, int argc);
CommandHandler<TestClass1, FUNC> m_commandHandler;
};
class TestClass2
{
public:
TestClass2()
: m_commandHandler("TestClass2")
{
}
~TestClass2()
{
commandServer_s->removeHandler(m_commandHandler.getHandlerName());
}
void registerCommandHandler()
{
commandServer_s->registerNewHandler(&m_commandHandler);
m_commandHandler.addCommand("add-status", "just for test", *this, &TestClass2::testFunc);
}
void deRegisterCommandHandler()
{
m_commandHandler.removeCommand("add-status");
commandServer_s->removeHandler(m_commandHandler.getHandlerName());
}
void testFunc(string & param, int argc)
{
INFO_LOG("param is %s, argc is %d!/n", param.c_str(), argc);
}
private:
typedef void (TestClass2::*FUNC) (string & param, int argc);
CommandHandler<TestClass2, FUNC> m_commandHandler;
};
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
{
INFO_LOG("Test begin!/n");
TestClass1 testClass1;
TestClass2 testClass2;
testClass1.registerCommandHandler();
testClass2.registerCommandHandler();
string runtimeData = "runtime";
int cnt = 100;
commandServer_s->handleCommand("show-status", runtimeData, cnt++);
commandServer_s->handleCommand("add-status", runtimeData, cnt);
testClass1.deRegisterCommandHandler();
testClass2.deRegisterCommandHandler();
INFO_LOG("Test end!/n");
}
// Makefile
SRC := $(wildcard *.cc)
OBJ := $(patsubst %.cc, %.o, $(SRC))
BIN := test
CC := g++
LD := g++
RM = rm -fr
CPPFLAG := -I./
CXXFLAG := -g -O3 -Wall -Werror
LDFLAG := -L./
$(BIN) : $(OBJ)
@echo "Linking $@!"
$(LD) -o $@ $^ $(LDFLAG)
@echo "Link $@ done!"
%.o : %.cc
@echo "Compiling $@!"
$(CC) -c -o $@ $< $(CPPFLAG) $(CXXFLAG)
@echo "Compile $@ done!"
.PHONE : clean
clean:
$(RM) $(BIN)
$(RM) $(OBJ)