设计模式:责任链模式

目录

一、引言

二、模式定义与核心思想

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

四、模式结构与组件

五、代码样例

六、优缺点分析

七、结语


一、引言

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

后来小明得知,请假天数在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. 避免循环引用。

七、结语

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


完~

相关推荐
晨米酱7 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机12 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机13 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机13 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤13 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式