当前位置:编程学习 > C/C++ >>

行为型模式之Chain of Responsibility模式

概要
程序中经常出现这样的逻辑,收到XX请求,进行XX相关的响应处理,收到YY请求,则进行YY的响应处理。请求与响应之间彼此配对,所以代码也往往会为这种配对提供一对一的对应关系。比如说之前说过的Command模式中,一种Command会跟一个Performer对应起来确保这种逻辑关系。那如果某个请求该如何响应是未知或动态决定的,如何处理呢?答案之一,用一堆条件来判断限制啊?很多情况下,没错,应该这样做。但有时这样做会不会太累啊?有没有什么其他方案呢?Chain of Responsibility模式就是选择之一,通过对所有的响应方建立职责链,请求方不需要知道由哪个响应来执行,只需要把请求丢给职责链,职责链的每个元素都有可以执行,可以传递,当然也可以中止传递。
 
目的
避免请求方耦合于执行方,请求方可以不需要知道哪个目标会执行该请求,而只需要把请求传递给职责链就ok。执行方被动态串联形成职责链,执行条件由每个元素自己控制。
 
实例
想到这样一个伪例子,当收到的命令小于Command1或者等于Command3时,执行Performer1,当命令大于Command1,小于Command5并且不等于Command3时,执行Performer2,当命令等于Command7时,也执行Performer2,当命令大于Command5,小于Command9并且不等于Command7时,执行Performer3。好纠结的条件啊,其实代码倒还好,看下实现:
[cpp]  
void handle_request(int cmd) {  
       if (cmd <= COMMAND_1) {  
            perform1.action();  
      }      else if (cmd <= COMMAND_5) {  
             if (cmd == COMMAND_3) {  
                  perform1.action();  
            } else {  
                  perform2.action();  
            }  
      }      else if (cmd <= COMMAND_9) {  
             if (cmd == COMMAND_7) {  
                  perform2.action();  
            } else {  
                  perform3.action();  
            }  
      }      else {  
      }  
}  
确实处理逻辑还不算太负责,但是万一又来n个条件逻辑呢,所以代码只会变得越来越复杂,perform的触发方会很纠结与这种代码的维护与测试。那用Chain of Responsibility模式呢?怎么实现?先类图设计:
 
 
太抽象了,还是直接看下代码怎么实现的,首先Handler类提供handle_request接口,并提供set_successor方法可以设置职责链上下一个Handler是谁,每个具体的Handler子类实现自己的handle_request,其中关注某个performer运行需要的条件就可以了,当然也别忘了在不符合条件时把cmd传给下一个Handler。
[cpp]  
class Handler {  
public:  
       virtual void handle_request(int cmd) = 0;  
  
       public void set_successor(Handler* successor)  
      {  
            m_successor = successor;  
      }  
protected:  
      Handler* m_successor;  
};  
  
class ConcreteHandler1 : public Handler {  
public:  
       void handle_request(int cmd) {  
             if (cmd <= COMMAND_1 || cmd == COMMAND_3) {  
                  performer1.action();  
            } else if (m_successor != NULL) {  
                  m_successor->handle_request(cmd);  
            }       
      }  
};  
  
class ConcreteHandler2 : public Handler {  
public:  
       void handle_request(int cmd) {  
             if (cmd <= COMMAND_5 || cmd == COMMAND_7) {  
                  performer2.action();  
            } else if (m_successor != NULL) {  
                  m_successor->handle_request(cmd);  
            }       
      }  
};  
  
class ConcreteHandler3 : public Handler {  
public:  
       void handle_request(int cmd) {  
             if (cmd <= COMMAND_9) {  
                  performer3.action();  
            } else if (m_successor != NULL) {  
                  m_successor->handle_request(cmd);  
            }       
      }  
};  
具体使用可以如下,都可以通过h1来处理request,最后cmd都会由对应的Handler进行处理:
[cpp]  
Handler* h1 = new ConcreteHandler1();  
Handler* h2 = new ConcreteHandler2();  
Handler* h3 = new ConcreteHandler3();  
h1->setSuccessor(h2);  
h2->setSuccessor(h3);  
  
h1->handle_request(COMMAND_1);  
h1->handle_request(COMMAND_3);  
h1->handle_request(COMMAND_5);  
h1->handle_request(COMMAND_7);  
h1->handle_request(COMMAND_9);  
可能有人会发现,每个handle_request都需要去关心通过m_successor来转发有点麻烦,万一哪个地方忘了处理,那职责链就断了,让我们看看是否可以想点办法来改善这一点,看下如下代码是不是让实现更简单更健壮了:
[cpp] 
class Handler {  
public:  
       void handle_request(int cmd) {  
             if (handle_request_impl(cmd) == false && m_successor != NULL) {  
                  m_successor->handle_request(cmd);  
            }  
      }  
       virtual bool handle_request_impl(int cmd) = 0;  
  
       public void set_successor(Handler* successor)  
      {  
            m_successor = successor;  
      }  
private:  
      Handler* m_successor;  
};  
  
class ConcreteHandler1 : public Handler {  
public:  
       bool handle_request_impl(int cmd) {  
             if (
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,