函数对象和模版实现责任链模式

最近闲着没事, 整理原来代码时候发现用函数对象加上模版实现责任链模式的方法很值得温习, 重新理了一下, 整个过程如下:

 

测试结果:

[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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值