责任链模式(Chain of Responsibility)

这篇具有很好参考价值的文章主要介绍了责任链模式(Chain of Responsibility)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

别名

命令链(Chain of Command)。

定义

责任链是一种行为设计模式允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者

前言

1. 问题

假如你正在开发一个在线订购系统。你希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户也拥有所有订单的完全访问权限。

简单规划后,你会意识到这些检查必须依次进行。只要接收到包含用户凭据的请求,应用程序就可尝试对进入系统的用户进行认证。但如果由于用户凭据不正确而导致认证失败,那就没有必要进行后续检查了。

责任链模式(Chain of Responsibility)

随着功能不断迭代,检查代码逐渐变得越来越混乱,修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当你希望复用这些检查步骤来保护其他系统组件时,你只能复制部分代码,因为这些组件只需要部分而非全部的检查步骤。

系统会变得让人非常费解,而且其维护成本也会激增。你在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。

2. 解决方案

与许多其他行为设计模式一样,「责任链模式」会将特定行为转换为被称作处理者的独立对象。在上述示例中,每个检查步骤都可被抽取为仅有单个方法的类,并执行检查操作。请求及其数据则会被作为参数传递给该方法。

模式建议你将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。

最重要的是:处理者可以决定不再沿着链传递请求,这可高 效地取消所有后续处理步骤。

在我们的订购系统示例中,处理者会在进行请求处理工作后决定是否继续沿着链传递请求。如果请求中包含正确的数据,所有处理者都将执行自己的主要行为,无论该行为是身份验证还是数据缓存。

责任链模式(Chain of Responsibility)

不过还有一种稍微不同的方式(也是更经典一种),那就是处理者接收到请求后自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见。

所有处理者类均实现同一接口是关键所在。每个具体处理者仅关心下一个包含 execute 执行 方法的处理者。 这样一来,你就可以在运行时使用不同的处理者来创建链,而无需将相关代码与处理者的具体类进行耦合。

结构

责任链模式(Chain of Responsibility)

  1. 处理者(Handler)声明了所有具体处理者的通用接口。该接口通常仅包含单个方法用于请求处理,但有时其还会包含一个设置链上下个处理者的方法。
  2. 基础处理者(Base Handler)是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。通常情况下,该类中定义了一个保存对于下个处理者引用的成员变量。客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。该类还可以实现默认的处理行为:确定下个处理者存在后再将请求传递给它。
  3. 具体处理者(Concrete Handlers)包含处理请求的实际代码。每个处理者接收到请求后,都必须决定是否进行处理,以及是否沿着链传递请求。处理者通常是独立且不可变的,需要通过构造函数一次性地获得所有必要地数据。
  4. 客户端(Client)可根据程序逻辑一次性或者动态地生成链。值得注意的是,请求可发送给链上的任意一个处理者,而非必须是第一个处理者。

适用场景

  • 当程序需要使用不同方式处理不同种类请求,而且请求类型和顺序预先未知时,可以使用责任链模式。

该模式能将多个处理者连接成一条链。接收到请求后,它会“询问”每个处理者是否能够对其进行处理。这样所有处理者都有机会来处理请求。

  • 当必须按顺序执行多个处理者时,可以使用该模式。

无论你以何种顺序将处理者连接成一条链,所有请求都会严格按照顺序通过链上的处理者。

  • 如果所需处理者及其顺序必须在运行时进行改变,可以使用责任链模式。该类需要有一个成员变量来存储指向链上下个处理者的引用。你可以将其设置为不可变类。但如果你打算在运行时对链进行改变,则需要定义一个设定方法来修改引用成员变量的值。

如果在处理者类中有对引用成员变量的设定方法,你将能动态地插入和移除处理者,或者改变其顺序。

实现方式

  1. 声明处理者接口并描述请求处理方法的签名。确定客户端如何将请求数据传递给方法。最灵活的方式是将请求转换为对象,然后将其以参数的形式传递给处理函数。
  2. 为了在具体处理者中消除重复的样本代码,你可以根据处理者接口创建抽象处理者基类。该类需要有一个成员变量来存储指向链上下个处理者的引用。你可以将其设置为不可变类。但如果你打算在运行时对链进行改变,则需要定义一个设定方法来修改引用成员变量的值。为了使用方便,你还可以实现处理方法的默认行为。如果还有剩余对象,该方法会将请求传递给下个对象。具体处理者还能够通过调用父对象的方法来使用这一行为。
  3. 依次创建具体处理者子类并实现其处理方法。每个处理者在 接收到请求后都必须做出两个决定: a.是否自行处理这个请求是否将该请求沿着链进行传递。
  4. 客户端可以自行组装链,或者从其他对象处获得预先组装好的链。在后一种情况下,你必须实现工厂类以根据配置或环境设置来创建链。
  5. 客户端可以触发链中的任意处理者,而不仅仅是第一个。请求将通过链进行传递,直至某个处理者拒绝继续传递,或者请求到达链尾。
  6. 由于链的动态性,客户端需要准备好处理以下情况:
    1. 链中可能只有单个链接。
    2. 部分请求可能无法到达链尾。
    3. 其他请求可能直到链尾都未被处理。

优点

  • 你可以控制请求处理的顺序。
  • 单一职责原则。你可对发起操作和执行操作的类进行解耦。
  • 开闭原则。你可以在不更改现有代码的情况下在程序中新增 处理者。

缺点

部分请求可能未被处理。

BaseHandler.hpp

#ifndef F52BFA24_4290_4919_A52A_DD89BBD73E6A
#define F52BFA24_4290_4919_A52A_DD89BBD73E6A

#include <string>
#include "Handler.hpp"
class BaseApprover : public ApproverInterface {
 public:
    BaseApprover(double mpa, std::string n) : max_processible_amount_(mpa), name_(n), superior_(nullptr) {}
    // 设置上级
    void setSuperior(ApproverInterface* superior) {
        superior_ = superior;
    }
    // 处理票据
    void handleRequest(double amount) {
        // 可处理时直接处理即可
        if (amount <= max_processible_amount_) {
            printf("%s处理了该票据, 票据面额:%f\n", name_.c_str(), amount);
            return;
        }
        // 无法处理时移交给上级
        if (superior_ != nullptr) {
            printf("%s无权处理, 转交上级...\n", name_.c_str());
            superior_->handleRequest(amount);
            return;
        }
        // 最上级依然无法处理时报错
        printf("无人有权限处理该票据, 票据金额:%f\n", amount);
    }

 private:
    double max_processible_amount_;  // 可处理的最大面额
    std::string name_;
    ApproverInterface* superior_;
};

#endif /* F52BFA24_4290_4919_A52A_DD89BBD73E6A */

Handler.hpp

#ifndef C299C914_BF51_4129_AB44_E94EFF3E1C1E
#define C299C914_BF51_4129_AB44_E94EFF3E1C1E

class   ApproverInterface
{
    private:
        
    public:
        virtual void setSuperior(ApproverInterface * superior) = 0;
        virtual void handleRequest(double amount) = 0;
    
};

#endif /* C299C914_BF51_4129_AB44_E94EFF3E1C1E */

ConcreteHandler.hpp

#ifndef CB6528AE_058B_4392_A96A_463A522CD622
#define CB6528AE_058B_4392_A96A_463A522CD622

#include <string>
#include <cstdio>
#include "BaseHandler.hpp"

// 具体处理者: 组长(仅处理面额<=10的票据)
class GroupLeader : public BaseApprover {
 public:
    explicit GroupLeader(std::string name) : BaseApprover(10, name) {}
};

// 具体处理者: 经理(仅处理面额<=100的票据)
class Manager : public BaseApprover {
 public:
    explicit Manager(std::string name) : BaseApprover(100, name) {}
};


// 具体处理者: 老板(仅处理面额<=1000的票据)
class Boss : public BaseApprover {
 public:
    explicit Boss(std::string name) : BaseApprover(1000, name) {}
};

#endif /* CB6528AE_058B_4392_A96A_463A522CD622 */

main.cpp文章来源地址https://www.toymoban.com/news/detail-509781.html

#include "ConcreteHandler.hpp"

int main() {
    // 请求处理者: 组长、经理和老板
    GroupLeader* group_leader = new GroupLeader("张组长");
    Manager* manager = new Manager("王经理");
    Boss* boss = new Boss("李老板");

    // 设置上级
    group_leader->setSuperior(manager);
    manager->setSuperior(boss);

    // 不同面额的票据统一先交给组长审批
    group_leader->handleRequest(8);
    group_leader->handleRequest(88);
    group_leader->handleRequest(888);
    group_leader->handleRequest(8888);

    delete group_leader;
    delete manager;
    delete boss;

    return 0;
}

到了这里,关于责任链模式(Chain of Responsibility)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式——责任链模式(Chain of Responsibility Pattern)+ Spring相关源码

    类型: 行为型模式 每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。 目的: 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所

    2024年02月05日
    浏览(57)
  • 【设计模式-05】Facade门面Mediator调停者 | Decorator装饰器 | Chain Of Responsibility责任链

    一般是系统内部相互交错,比如 消息中间件(MQ) 就是这种设计模式,对各个功能或系统之间进行解耦。 业务场景:论坛或者博客发表帖子或者评论,对敏感词过滤处理。使用责任链的模式进行过滤处理。 把变化的进行封装处理 核心代码实现 GitHub - jxaufang168/Design-Patterns: 设计

    2024年01月19日
    浏览(111)
  • 设计模式—职责链模式(Chain of Responsibility)

    目录 思维导图 什么是职责链模式? 有什么优点呢? 有什么缺点呢? 什么场景使用呢? 代码展示 ①、职责链模式 ②、加薪代码重构 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有

    2024年02月10日
    浏览(37)
  • 设计模式--职责链模式(Chain of Responsibility Pattern)

    职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它为请求创建了一个接收者对象的链。 这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在职责链模式中,通常每个接收者都包含对另一个接收者的引用。如果

    2024年02月20日
    浏览(37)
  • Java设计模式—责任链模式(Chin of Responsibility)

    目录 前言 一、责任链模式的简介 二、责任链模式的概念 三、责任链模式的作用 四、责任链模式的优、缺点 1.责任链模式的优点 2.责任链模式的缺点 五、责任链模式的应用场景 六、代码案例 UML类图  1.定义一个请求枚举类  2.定义一个请求类 3.定义一个抽象处理接口 4、定

    2024年02月08日
    浏览(35)
  • 1079 Total Sales of Supply Chain (PAT甲级)

    A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone involved in moving a product from supplier to customer. Starting from one root supplier, everyone on the chain buys products from one\\\'s supplier in a price Pand sell or distribute them in a price that is r% higher than P. Only the

    2024年02月09日
    浏览(32)
  • LeetCode646. Maximum Length of Pair Chain——动态规划

    You are given an array of n pairs pairs where pairs[i] = [lefti, righti] and lefti righti. A pair p2 = [c, d] follows a pair p1 = [a, b] if b c. A chain of pairs can be formed in this fashion. Return the length longest chain which can be formed. You do not need to use up all the given intervals. You can select pairs in any order. Example 1: Input: pairs = [[

    2024年02月22日
    浏览(48)
  • 对平稳马尔可夫链(stationary distribution of a Markov chain)的学习

    首先介绍马尔可夫链的 平稳分布 :   给定一个马尔可夫链,其状态空间存在概率分布π=π(s),且转移矩阵和转移概率P=p(i,j),若满足 π=πP (平衡方程),则称π是该马尔可夫链的平稳分布,或称为转移阵P的 不变测度 。   如果马尔可夫链的存在平稳分布,并且其初始

    2024年02月05日
    浏览(40)
  • 使用思维链(Chain-of-thoughts)提示在大型语言模型中引出推理

    语言模型(LM)在NLP领域的发展速度非常快,特别是在大型语言模型(LLM)方面:当语言模型具有大量参数或权重/系数时,它们被称为“大型”。这些“大型”语言模型拥有处理和理解大量自然语言数据的能力。 LLM被用于一系列自然语言任务,如文本摘要、情感分析、主题分类、

    2024年02月05日
    浏览(42)
  • 设计模式-责任链模式

    遇到一个面试的场景题目,让实现税率的计算 请使用Java语言实现如下税率计算: 1~5000 税率 0 5001~8000 3% 8001~17000 10% 17001~30000 20% 30001~40000 25% 40001~60000 30% 60001~85000 35% 85001~ 45% 要求 ⅰ. 逻辑正确,代码优雅 ⅱ. 可扩展性,考虑区间的变化,比如说起征点从5000变成10000等等,或者

    2024年02月11日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包