设计模式:责任链模式

目录

一、引言

二、模式定义与核心思想

三、责任链模式的纯与不纯

四、模式结构与组件

五、代码样例

六、优缺点分析

七、结语


一、引言

举个例子,小明是公司的一名员工,最近身体不舒服,需要请假一个月。他拿着请假条,先去找小组长签字。小组长签完字后,让他拿着请假条去找部门经理签字。部门经理签完字后,又让他拿着请假条去找总经理签字。直到总经理也签了字,小明的请假才算正式获批。

后来小明得知,请假天数在3天以内,直接找小组长签字即可,3~7天需要小组长和部门经理签字,超过7天需要小组长、部门经理和总经理签字。

所以,以上的处理过程,客户端代码的逻辑如下:

可以看到,在客户端是需要做出很多判断的。如果处理链条一改变,比如多了老板审批这一步的话,客户端是需要再加一个判断的。好的代码应该是高内聚低耦合的,也就是说,处理模块的改变不影响到客户端。追求的是小明一旦提交了请假申请,那么他只需要等待结果就好了,而不用跑去问这个哪个的。在这种场景下,应用责任链模式就很合适。

二、模式定义与核心思想

责任链模式的定义就是,避免将请求的发送者与接收者耦合,让多个对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

三、责任链模式的纯与不纯

经典的责任链模式为,当请求沿着处理链传递时,一旦有处理器可以对该请求进行处理,那么就不再继续往后传递。上面给出的定义就是经典责任链模式的定义,或者说是纯的责任链模式。与之对应的就是不纯的责任链模式。不纯的责任链模式就是,处理器可以处理请求的一部分,然后继续传递给下一个处理器。引言中请假的例子就是不纯的责任链模式。不管是纯与不纯,不论好坏,都有各自的应用场景,我们该关心的是这两种模式哪一种能更好的解决我们的问题。

四、模式结构与组件

责任链模式的结构和组件基本上是固定的,一个抽象的处理类,若干个具体处理类继承这个抽象的处理类,然后一个客户端发起请求。

五、代码样例

下面通过一个例子来说明:

需求:我们有一个文本处理的责任链,处理链中有两个处理器:

  1. 清除首尾空格处理器(TrimProcessor):清除文本首尾空格(部分处理),然后传递给下一个处理器。
  2. 大写处理器(UpperProcessor):将文本转为大写(另一种处理)。

处理过程: 输入: " hello world " 经过TrimProcessor:变成"hello world"(去除了首尾空格) 然后传递给UpperProcessor:变成"HELLO WORLD"。

cpp 复制代码
//chain.hpp
#ifndef chain_hpp
#define chain_hpp

#include <iostream>
#include <memory>
#include <string>
#include <algorithm>

class Request {
public:
    Request(std::string data) : _data(data) {}
    std::string getData() {
        return _data;
    }
    void setData(std::string &data) {
        _data = data;
    }
private:
    std::string _data;
};

class Processor {
public:
    Processor() : _next(nullptr) {}
    virtual void handleRequest(Request &request) = 0;
    void setNext(const std::shared_ptr<Processor> &next) {
        this->_next = next;
    }
protected:
    std::shared_ptr<Processor> _next;
};

class TrimProcessor : public Processor {
public:
    void handleRequest(Request &request) override {
        std::string data = request.getData();
        std::string result = trim(data);
        request.setData(result);
        if (_next) {
            _next->handleRequest(request);
        }
    }
private:
    std::string trim(const std::string &data) {
        size_t first = data.find_first_not_of(' ');
        if (first == std::string::npos) {
            return "";
        }
        size_t last = data.find_last_not_of(' ');
        return data.substr(first, last - first + 1);
    }
};

class UpperProcessor : public Processor {
public:
    void handleRequest(Request &request) override {
        std::string data = request.getData();
        std::string result = toUpperCase(data);
        request.setData(result);
    }
private:
    std::string toUpperCase(const std::string &data) {
        std::string result;
        for (auto &c : data) {
            result += toupper(c);
        }
        return result;
    }
};

#endif /* chain_hpp */

//main.cc
#include "chain.hpp"

int main()
{
    std::shared_ptr<Processor> chain = std::make_shared<TrimProcessor>();
    chain->setNext(std::make_shared<UpperProcessor>());
    Request request("     -hello world-  ");
    chain->handleRequest(request);
    std::cout << request.getData() << std::endl; // Output: HELLO WORLD
    return 0;
}

六、优缺点分析

优点:

  1. 将请求的发送者和处理者解耦。
  2. 可以灵活的增减处理器。
  3. 符合开闭原则。

缺点:

  1. 缺少尾处理器,有的请求可能无法处理------添加默认处理器兜底。
  2. 处理链过长,会影响到性能------控制处理链长度。
  3. 避免循环引用。

七、结语

责任链模式如同装配流水线,让请求在不同工位间流转处理。掌握这一设计模式,在遇到相应的场景时,可以迅速提升我们代码的逼格。


完~

相关推荐
小凯 ོ1 小时前
实战原型模式案例
java·后端·设计模式·原型模式
TechNomad2 小时前
设计模式:适配器模式(Adapter Pattern)
设计模式·适配器模式
Leo来编程4 小时前
设计模式9-责任链模式
责任链模式
指针刺客4 小时前
嵌入式筑基之设计模式
开发语言·c++·设计模式
简色4 小时前
领悟8种常见的设计模式
java·后端·设计模式
牛奶咖啡135 小时前
学习设计模式《二十四》——访问者模式
学习·设计模式·访问者模式·认识访问者模式·访问者模式的优缺点·何时选用访问者模式·访问者模式的使用示例
TechNomad5 小时前
设计模式:组合模式(Composite Pattern)
设计模式·组合模式
找不到、了6 小时前
Java设计模式之《外观模式》
java·设计模式·外观模式
秋难降15 小时前
代码界的 “建筑师”:建造者模式,让复杂对象构建井然有序
java·后端·设计模式