• [设计模式] 设计模式课程(十九)--职责链模式


    概述

    • 属于行为型
    • 程序需要按顺序处理多个请求时
    • 程序需要使用不同方式处理不同种类的请求,且请求类型和顺序预先未知时,将多个处理者连成一条链,接到请求后,询问每个处理者是否能对其进行处理
    • 沿责任链传递请求,直到有一个对象处理为止。使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系

    • 一个请求可能会被多个对象处理,但每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求者与接受者的紧耦合
    • 如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使二者解耦
    • 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止
    • 使用多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递请求,知道有一个对象处理它为止
    • Chain of Responsibility 模式的应用场合在于“一个请求可能有多个接受者,但最后真正的接受者只有一个”,这时候请求发送者与接受者的耦合有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好地应对变化
    • 应用了Chain of Responsibility 模式后,对象的职责分派将更具灵活性,可在运行时动态添加/修改请求的处理职责
    • 如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制,这也是每一个接收对象的职责,而不是发出请求的对象的责任

    场景

    • 拨打技术支持电话时,多名接听人员接力处理
    • 为活动的GUI元素显示上下文帮助信息。当用户鼠标移动到某个元素并按下F1键时,程序检测到指针下的组件并对其发送帮助请求,该请求不断向上传递到该元素的所有容器,直到某个元素能显示帮助信息
    • Struct2的拦截器
    • jsp servlet 的 Filter
    • Tomca 对 Encoding 的处理

    结构

    • 处理者:声明了所有具体处理者的通用接口
    • 基础处理者:放置所有处理者共用的代码
    • 具体处理者:处理请求的实际代码,处理者接到具体请求后,决定是否处理,是否沿着链传递请求
    • 客户端:根据程序逻辑一次性或动态地生成链,请求可以发给链上的任一个处理者

     示例1

    ChainofResponsibility.cpp

    View Code
    • 举例:windows界面
    • 25行:用链表实现链,基类的多态指针指向自身,形成多态链表
    • 38-45行:整体处理

    示例2

     1 #include <iostream>
     2 #include <string>
     3 #include <vector>
     4 using namespace std;
     5 
     6 class Request{
     7     public:
     8         string m_strContent;
     9         int m_nNumber;
    10 };
    11 class Manager{
    12     protected:
    13         Manager* manager;
    14         string name;
    15     public:
    16         Manager(string temp){
    17             name = temp;
    18         }
    19     void SetSuccessor(Manager* temp){
    20         manager = temp;
    21     } 
    22     virtual void GetRequest(Request* request)=0;
    23 };
    24 class CommonManager:public Manager{
    25     public:
    26         CommonManager(string strTemp):Manager(strTemp){}
    27         virtual void GetRequest(Request* request){
    28             if(request->m_nNumber>=0 && request->m_nNumber<10){
    29                 cout<<name<<"处理了"<<request->m_nNumber<<"个请求"<<endl;
    30             }else{
    31                 manager->GetRequest(request);
    32             }
    33         }
    34 };
    35 class MajorDomo:public Manager{
    36     public:
    37         MajorDomo(string name):Manager(name){}
    38         virtual void GetRequest(Request* request){
    39             if(request->m_nNumber>=10){
    40                 cout<<name<<"处理了"<<request->m_nNumber<<"个请求"<<endl;
    41             }
    42         }
    43 };
    44 int main(){
    45     Manager* common = new CommonManager("张经理");
    46     Manager* major = new MajorDomo("李总监");
    47     common->SetSuccessor(major);
    48     Request* req = new Request();
    49     
    50     req->m_nNumber = 33;
    51     common->GetRequest(req);
    52     
    53     req->m_nNumber=3;
    54     common->GetRequest(req);
    55     
    56     return 0;
    57 }

    示例3

     1 // 处理者接口声明了一个创建处理者链的方法。还声明了一个执行请求的方法。
     2 interface ComponentWithContextualHelp is
     3     method showHelp()
     4 
     5 
     6 // 简单组件的基础类。
     7 abstract class Component implements ComponentWithContextualHelp is
     8     field tooltipText: string
     9 
    10     // 组件容器在处理者链中作为“下一个”链接。
    11     protected field container: Container
    12 
    13     // 如果组件设定了帮助文字,那它将会显示提示信息。如果组件没有帮助文字
    14     // 且其容器存在,那它会将调用传递给容器。
    15     method showHelp() is
    16         if (tooltipText != null)
    17             // 显示提示信息。
    18         else
    19             container.showHelp()
    20 
    21 
    22 // 容器可以将简单组件和其他容器作为其子项目。链关系将在这里建立。该类将从
    23 // 其父类处继承 showHelp(显示帮助)的行为。
    24 abstract class Container extends Component is
    25     protected field children: array of Component
    26 
    27     method add(child) is
    28         children.add(child)
    29         child.container = this
    30 
    31 
    32 // 原始组件应该能够使用帮助操作的默认实现...
    33 class Button extends Component is
    34     // ...
    35 
    36 // 但复杂组件可能会对默认实现进行重写。如果无法以新的方式来提供帮助文字,
    37 // 那组件总是还能调用基础实现的(参见 Component 类)。
    38 class Panel extends Container is
    39     field modalHelpText: string
    40 
    41     method showHelp() is
    42         if (modalHelpText != null)
    43             // 显示包含帮助文字的模态窗口。
    44         else
    45             super.showHelp()
    46 
    47 // ...同上...
    48 class Dialog extends Container is
    49     field wikiPageURL: string
    50 
    51     method showHelp() is
    52         if (wikiPageURL != null)
    53             // 打开百科帮助页面。
    54         else
    55             super.showHelp()
    56 
    57 
    58 // 客户端代码。
    59 class Application is
    60     // 每个程序都能以不同方式对链进行配置。
    61     method createUI() is
    62         dialog = new Dialog("预算报告")
    63         dialog.wikiPageURL = "http://..."
    64         panel = new Panel(0, 0, 400, 800)
    65         panel.modalHelpText = "本面板用于..."
    66         ok = new Button(250, 760, 50, 20, "确认")
    67         ok.tooltipText = "这是一个确认按钮..."
    68         cancel = new Button(320, 760, 50, 20, "取消")
    69         // ...
    70         panel.add(ok)
    71         panel.add(cancel)
    72         dialog.add(panel)
    73 
    74     // 想象这里会发生什么。
    75     method onF1KeyPress() is
    76         component = this.getComponentAtMouseCoords()
    77         component.showHelp()
    View Code

    示例4

      1 #include <iostream>
      2 #include <string> 
      3 #include <vector>
      4 /**
      5  * The Handler interface declares a method for building the chain of handlers.
      6  * It also declares a method for executing a request.
      7  */
      8 class Handler {
      9  public:
     10   virtual Handler *SetNext(Handler *handler) = 0;
     11   virtual std::string Handle(std::string request) = 0;
     12 };
     13 /**
     14  * The default chaining behavior can be implemented inside a base handler class.
     15  */
     16 class AbstractHandler : public Handler {
     17   /**
     18    * @var Handler
     19    */
     20  private:
     21   Handler *next_handler_;
     22 
     23  public:
     24   AbstractHandler() : next_handler_(nullptr) {
     25   }
     26   Handler *SetNext(Handler *handler) override {
     27     this->next_handler_ = handler;
     28     // Returning a handler from here will let us link handlers in a convenient
     29     // way like this:
     30     // $monkey->setNext($squirrel)->setNext($dog);
     31     return handler;
     32   }
     33   std::string Handle(std::string request) override {
     34     if (this->next_handler_) {
     35       return this->next_handler_->Handle(request);
     36     }
     37 
     38     return {};
     39   }
     40 };
     41 /**
     42  * All Concrete Handlers either handle a request or pass it to the next handler
     43  * in the chain.
     44  */
     45 class MonkeyHandler : public AbstractHandler {
     46  public:
     47   std::string Handle(std::string request) override {
     48     if (request == "Banana") {
     49       return "Monkey: I'll eat the " + request + ".
    ";
     50     } else {
     51       return AbstractHandler::Handle(request);
     52     }
     53   }
     54 };
     55 class SquirrelHandler : public AbstractHandler {
     56  public:
     57   std::string Handle(std::string request) override {
     58     if (request == "Nut") {
     59       return "Squirrel: I'll eat the " + request + ".
    ";
     60     } else {
     61       return AbstractHandler::Handle(request);
     62     }
     63   }
     64 };
     65 class DogHandler : public AbstractHandler {
     66  public:
     67   std::string Handle(std::string request) override {
     68     if (request == "MeatBall") {
     69       return "Dog: I'll eat the " + request + ".
    ";
     70     } else {
     71       return AbstractHandler::Handle(request);
     72     }
     73   }
     74 };
     75 /**
     76  * The client code is usually suited to work with a single handler. In most
     77  * cases, it is not even aware that the handler is part of a chain.
     78  */
     79 void ClientCode(Handler &handler) {
     80   std::vector<std::string> food = {"Nut", "Banana", "Cup of coffee"};
     81   for (const std::string &f : food) {
     82     std::cout << "Client: Who wants a " << f << "?
    ";
     83     const std::string result = handler.Handle(f);
     84     if (!result.empty()) {
     85       std::cout << "  " << result;
     86     } else {
     87       std::cout << "  " << f << " was left untouched.
    ";
     88     }
     89   }
     90 }
     91 /**
     92  * The other part of the client code constructs the actual chain.
     93  */
     94 int main() {
     95   MonkeyHandler *monkey = new MonkeyHandler;
     96   SquirrelHandler *squirrel = new SquirrelHandler;
     97   DogHandler *dog = new DogHandler;
     98   monkey->SetNext(squirrel)->SetNext(dog);
     99 
    100   /**
    101    * The client should be able to send a request to any handler, not just the
    102    * first one in the chain.
    103    */
    104   std::cout << "Chain: Monkey > Squirrel > Dog
    
    ";
    105   ClientCode(*monkey);
    106   std::cout << "
    ";
    107   std::cout << "Subchain: Squirrel > Dog
    
    ";
    108   ClientCode(*squirrel);
    109 
    110   delete monkey;
    111   delete squirrel;
    112   delete dog;
    113 
    114   return 0;
    115 }
    View Code
    Chain: Monkey > Squirrel > Dog
    
    Client: Who wants a Nut?
      Squirrel: I'll eat the Nut.
    Client: Who wants a Banana?
      Monkey: I'll eat the Banana.
    Client: Who wants a Cup of coffee?
      Cup of coffee was left untouched.
    
    Subchain: Squirrel > Dog
    
    Client: Who wants a Nut?
      Squirrel: I'll eat the Nut.
    Client: Who wants a Banana?
      Banana was left untouched.
    Client: Who wants a Cup of coffee?
      Cup of coffee was left untouched.

    参考

    https://refactoringguru.cn/design-patterns/chain-of-responsibility

  • 相关阅读:
    SSL证书指令
    重启机器解决SSL都要输入密码问题
    Nginx + Apache 反向代理
    Ubuntu Nginx安装
    Nginx配置文件详解
    Linux SSL 双向认证 浅解
    SSL 双向认证
    linux ssl 双向认证
    ubuntu apache2 ssl配置
    vi编辑器命令
  • 原文地址:https://www.cnblogs.com/cxc1357/p/12077331.html
Copyright © 2020-2023  润新知