程序员必知!责任链模式的实战应用与案例分析

news2025/1/11 14:19:56

程序员必知!责任链模式的实战应用与案例分析 - 程序员古德

责任链模式让多个对象依次处理请求,降低发送者和接收者的耦合度,以在线购物为例,用户提交订单需经多步验证,通过责任链模式,验证器按顺序处理请求,先用户身份,再支付方式,最后配送地址,任一验证失败即停止流程并反馈错误,责任链模式提升了代码的灵活性和可扩展性。

定义

程序员必知!责任链模式的实战应用与案例分析 - 程序员古德

责任链模式是一种行为设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,这些对象形成一个处理请求的链,client只需要将请求发送到链头即可。举一个业务中的例子:假设有一个在线购物网站,用户可以在网站上浏览商品并购买,在用户提交订单时,需要验证用户的身份、支付方式、配送地址等信息,可以使用责任链模式来处理这个流程,假设有以下验证器:

  1. 用户身份验证器:验证用户的身份信息是否正确。
  2. 支付方式验证器:验证用户的支付方式是否可用。
  3. 配送地址验证器:验证用户的配送地址是否有效。

可以将这些验证器组成一个责任链,并让它们依次处理请求,当用户提交订单时,责任链模式的第一个验证器(用户身份验证器)会首先处理请求,如果身份信息验证通过,它会将请求传递给下一个验证器(支付方式验证器),如果支付方式验证通过,再传递给下一个验证器(配送地址验证器),如果任何一个验证器不通过,整个流程就会停止,并返回相应的错误信息给用户。这样,就可以避免将请求发送者和接收者之间的耦合关系,使得代码更加灵活和可扩展。

代码案例

程序员必知!责任链模式的实战应用与案例分析 - 程序员古德

在未使用责任链模式的情况下,可能会将多个处理逻辑放在一个方法中,或者在一个方法中依次调用多个处理方法,这种方式会导致代码的可维护性和可扩展性降低,因为当需要添加或修改处理逻辑时,必须修改这个方法,下面是一个未使用责任链模式的反例代码:

// 订单验证类,未使用责任链模式  
public class OrderValidator {  
  
    // 验证用户身份  
    private boolean validateUser(User user) {  
        // 模拟验证逻辑  
        return user != null && user.isAuthenticated();  
    }  
  
    // 验证支付方式  
    private boolean validatePayment(Payment payment) {  
        // 模拟验证逻辑  
        return payment != null && payment.isAvailable();  
    }  
  
    // 验证配送地址  
    private boolean validateAddress(Address address) {  
        // 模拟验证逻辑  
        return address != null && address.isValid();  
    }  
  
    // 提交订单方法,包含所有验证逻辑  
    public String submitOrder(User user, Payment payment, Address address) {  
        if (!validateUser(user)) {  
            return "用户身份验证失败!";  
        }  
        if (!validatePayment(payment)) {  
            return "支付方式验证失败!";  
        }  
        if (!validateAddress(address)) {  
            return "配送地址验证失败!";  
        }  
        // 所有验证通过,处理订单  
        return "订单提交成功!";  
    }  
}  
  
// 客户端调用案例  
public class Client {  
    public static void main(String[] args) {  
        OrderValidator validator = new OrderValidator();  
          
        // 创建用户、支付方式和配送地址对象  
        User user = new User(); // 假设已经认证  
        Payment payment = new Payment(); // 假设可用  
        Address address = new Address(); // 假设有效  
  
        // 提交订单并打印结果  
        String result = validator.submitOrder(user, payment, address);  
        System.out.println(result); // 输出:订单提交成功!  
  
        // 尝试使用无效的用户提交订单  
        User invalidUser = null; // 无效用户  
        String invalidUserResult = validator.submitOrder(invalidUser, payment, address);  
        System.out.println(invalidUserResult); // 输出:用户身份验证失败!  
    }  
}  
  
// 假设存在的其他类  
class User {  
    public boolean isAuthenticated() {  
        // 模拟认证逻辑  
        return true;  
    }  
}  
  
class Payment {  
    public boolean isAvailable() {  
        // 模拟支付方式可用逻辑  
        return true;  
    }  
}  
  
class Address {  
    public boolean isValid() {  
        // 模拟地址验证逻辑  
        return true;  
    }  
}

在上面的代码中,OrderValidator 类负责处理订单提交前的所有验证逻辑,submitOrder 方法中依次调用了用户验证、支付方式验证和配送地址验证方法,如果任何一个验证失败,方法都会立即返回错误信息,只有当所有验证都通过时,才会返回成功信息。

client代码创建了一个订单验证器实例,并尝试使用不同的用户提交订单,第一次提交使用有效用户,因此成功,第二次提交使用无效用户(null),因此失败,并返回相应的错误信息。

这种方式的问题是,如果需要添加新的验证逻辑(比如库存验证),必须修改 submitOrder 方法,这违反了开闭原则(对扩展开放,对修改关闭),此外,如果验证逻辑变得复杂,submitOrder 方法会变得非常庞大和难以维护。

当使用责任链模式时,可以创建一个处理请求的链,每个链上的节点都有机会处理该请求,如果某个节点能够处理请求,则处理它并可能结束链的进一步处理,否则,它将请求传递给链上的下一个节点,以下是一个使用了责任链模式的正例代码实现:

// 抽象处理者角色  
abstract class Handler {  
    protected Handler successor; // 下一个处理者  
  
    public void setSuccessor(Handler successor) {  
        this.successor = successor;  
    }  
  
    public abstract void handleRequest(Request request); // 处理请求的抽象方法  
}  
  
// 具体处理者角色A - 用户验证  
class UserHandler extends Handler {  
    @Override  
    public void handleRequest(Request request) {  
        if (request instanceof UserRequest) {  
            UserRequest userRequest = (UserRequest) request;  
            if (userRequest.getUser() != null && userRequest.getUser().isAuthenticated()) {  
                System.out.println("用户验证通过!");  
            } else {  
                System.out.println("用户验证失败!");  
                return; // 验证失败,不再传递请求  
            }  
        }  
        // 如果本处理者处理后请求未被结束,则继续传递  
        if (successor != null) {  
            successor.handleRequest(request);  
        }  
    }  
}  
  
// 具体处理者角色B - 支付验证  
class PaymentHandler extends Handler {  
    @Override  
    public void handleRequest(Request request) {  
        if (request instanceof PaymentRequest) {  
            PaymentRequest paymentRequest = (PaymentRequest) request;  
            if (paymentRequest.getPayment() != null && paymentRequest.getPayment().isAvailable()) {  
                System.out.println("支付验证通过!");  
            } else {  
                System.out.println("支付验证失败!");  
                return; // 验证失败,不再传递请求  
            }  
        }  
        // 如果本处理者处理后请求未被结束,则继续传递  
        if (successor != null) {  
            successor.handleRequest(request);  
        }  
    }  
}  
  
// 具体处理者角色C - 地址验证  
class AddressHandler extends Handler {  
    @Override  
    public void handleRequest(Request request) {  
        if (request instanceof AddressRequest) {  
            AddressRequest addressRequest = (AddressRequest) request;  
            if (addressRequest.getAddress() != null && addressRequest.getAddress().isValid()) {  
                System.out.println("地址验证通过!");  
            } else {  
                System.out.println("地址验证失败!");  
                return; // 验证失败,不再传递请求  
            }  
        }  
        // 正常情况下,这里可以处理请求或结束处理,但为了示例简单性,不在这里做任何额外处理  
    }  
}  
  
// 请求接口  
interface Request {  
}  
  
// 用户请求  
class UserRequest implements Request {  
    private User user;  
  
    public UserRequest(User user) {  
        this.user = user;  
    }  
  
    public User getUser() {  
        return user;  
    }  
}  
  
// 支付请求  
class PaymentRequest implements Request {  
    private Payment payment;  
  
    public PaymentRequest(Payment payment) {  
        this.payment = payment;  
    }  
  
    public Payment getPayment() {  
        return payment;  
    }  
}  
  
// 地址请求  
class AddressRequest implements Request {  
    private Address address;  
  
    public AddressRequest(Address address) {  
        this.address = address;  
    }  
  
    public Address getAddress() {  
        return address;  
    }  
}  
  
// 用户类  
class User {  
    private boolean authenticated;  
  
    public User(boolean authenticated) {  
        this.authenticated = authenticated;  
    }  
  
    public boolean isAuthenticated() {  
        return authenticated;  
    }  
}  
  
// 支付类  
class Payment {  
    private boolean available;  
  
    public Payment(boolean available) {  
        this.available = available;  
    }  
  
    public boolean isAvailable() {  
        return available;  
    }  
}  
  
// 地址类  
class Address {  
    private boolean valid;  
  
    public Address(boolean valid) {  
        this.valid = valid;  
    }  
  
    public boolean isValid() {  
        return valid;  
    }  
}  
  
// 客户端调用案例  
public class Client {  
    public static void main(String[] args) {  
        // 创建责任链  
        Handler userHandler = new UserHandler();  
        Handler paymentHandler = new PaymentHandler();  
        Handler addressHandler = new AddressHandler();  
        userHandler.setSuccessor(paymentHandler);  
        paymentHandler.setSuccessor(addressHandler);  
  
        // 创建请求并发送给责任链  
        User user = new User(true);  
        Payment payment = new Payment(true);  
        Address address = new Address(true);  
  
        // 发送用户请求  
        userHandler.handleRequest(new UserRequest(user));  
  
        // 发送支付请求  
        userHandler.handleRequest(new PaymentRequest(payment));  
  
        // 发送地址请求  
        userHandler.handleRequest(new AddressRequest(address));  
  
        // 尝试使用无效用户发送请求  
        User invalidUser = new User(false);  
        userHandler.handleRequest(new UserRequest(invalidUser));  
    }  
}

在上述代码中,创建了三个具体处理者(UserHandler, PaymentHandler, AddressHandler),它们分别处理用户验证、支付验证和地址验证,每个处理者都实现了抽象处理者Handler定义的接口,并且可以在处理请求时将请求传递给链中的下一个处理者。

在client中创建了一个责任链,每个请求都被传递给链中的适当处理者,如果处理者能够处理该请求,则处理它,否则将其传递给下一个处理者,当客户端尝试使用无效用户发送请求时,用户验证处理者会捕获这个条件并输出错误消息,同时停止请求的进一步处理。

核心总结

程序员必知!责任链模式的实战应用与案例分析 - 程序员古德

责任链模式是一种行为设计模式,它允许对象对请求进行处理,或者将其传递给链中的下一个处理者,这种模式可以消除请求的发送者和接收者之间的耦合,它如下特点:

优点

  1. 降低耦合度:请求者不需要知道具体是哪个对象处理了请求,只需将请求发送到链上即可。
  2. 灵活性高:通过改变链内的成员或调整它们的顺序,可以动态地新增或删除责任。
  3. 明确各职责:每个处理者都清楚自己的职责,只处理自己感兴趣或能处理的请求。

缺点

  1. 请求可能得不到处理:如果链上的所有处理者都不处理请求,请求可能会直接结束,没有明确的反馈。
  2. 性能问题:对于长链或复杂处理,可能会导致处理时间增长,影响性能。
  3. 调试困难:由于请求可能在多个处理者之间传递,当出现问题时,定位问题可能会比较困难。

使用建议

  1. 在明确各处理者职责和处理顺序的情况下使用。
  2. 避免过长的责任链,以减少性能损失和调试难度。
  3. 当请求可能得不到处理时,应有相应的反馈或默认处理机制。

完!

关注我,每天学习互联网编程技术 - 程序员古德

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1361905.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

odoo16 连接postgresql错误

odoo16 连接postgresql错误 odoo16 用odoo15的环境出错,看到是psycopg2.OperationalError分析是postgresql版本问题,安装了13版本,还是出错,多版本共存问题如下: Traceback (most recent call last):File "D:\o…

@JsonFormat与@DateTimeFormat

JsonFormat注解很好的解决了后端传给前端的格式,我们通过使用 JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题 其次,另一个问题是,我们在使用WEB服务的时,可 能会需要用到,传入时间给后台&am…

书生·浦语大模型实战营第一次课堂笔记

书生浦语大模型全链路开源体系。大模型是发展通用人工智能的重要途径,是人工通用人工智能的一个重要途径。书生浦语大模型覆盖轻量级、重量级、重量级的三种不同大小模型,可用于智能客服、个人助手等领域。还介绍了书生浦语大模型的性能在多个数据集上全面超过了相似量级或相近…

算法训练第六十天|84.柱状图中最大的矩形

84.柱状图中最大的矩形: 题目链接 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 示例 : 输入:heights [2,1,5,6,2,3] 输出…

基于JavaWeb+SSM+Vue家政项目微信小程序系统的设计和实现

基于JavaWebSSMVue家政项目微信小程序系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2…

Mathtype7.4安装与嵌入WPS

文章目录 Mathtype安装教程(7.4)Mathtype简介Mathtype下载安装软件下载软件安装运行MathType.exe运行注册表 Mathtype嵌入wps Mathtype安装教程(7.4) Mathtype简介 MathType是一款强大的数学公式编辑器,适用于教育教…

【大数据实验系列】一文轻松搞定云服务器Centos8.x下安装MySQL5.x版本,以阿里云服务器为例!(超详细安装流程)

1. 文章主要内容 本篇博客主要涉及云服务器(以阿里云服务器为例子)Centos8.x下安装MySQL软件。(通读本篇博客需要10分钟左右的时间)。 本篇博客内容参考于:centOS8安装MySql5.7 2. 详细安装教程 2.1 MySQL rpm源包下载 我们首先点击…

玩转爱斯维尔 LaTeX 模板:定制技巧一网打尽!

简介 关于 LaTeX 小编写过一些推文: 适合撰写课程论文的 LaTeX 模板; LaTeX 常用数学符号汇总; 免费升级 overleaf 高级账户!; 如何下载使用期刊的 LaTeX 模板 本文基于常用的 Elsevier 期刊模板,小编分享个人常用的使用技巧&#xff0…

SpringCloud-高级篇(十一)

(1)搭建Redis-主从架构 前面我们实现了Redis的持久化,解决了数据安全问题,但是还有需要解决的问题,下面学习Redis的主从集群,解决Redis的并发能力的问题 Redis的集群往往是主从集群,Redsi为什么…

时间序列预测 — LSTM实现多变量多步负荷预测(Tensorflow):多输入多输出

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 ​1.3 缺失值分析 2 构造训练数据 3 LSTM模型训练 4 LSTM模型预测 4.1 分量预测 4.2 可视化 1 数据处理 1.1 导入库文件 import time import datetime import pandas as pd import numpy as np import matplotlib.p…

C++八股学习心得.6

1.C 异常处理 异常是程序在执行期间产生的问题。C 异常是指在程序运行时发生的特殊情况 异常提供了一种转移程序控制权的方式。C 异常处理涉及到三个关键字:try、catch、throw。 throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来…

给Flutter + FireBase 增加 badge 徽章,App启动器 通知红点。

在此之前需要配置好 firebase 在flutter 在项目中。(已经配置好的可以忽略此提示) Firebase 配置教程:flutter firebase 云消息通知教程 (android-安卓、ios-苹果)_flutter firebase_messaging ios环境配置-CSDN博客 由于firebase 提供的消息…

3D空间漫游技术的日趋成熟,让博物馆数字化大放异彩!

随着科技的飞速发展,互联网已经成为人们生活中不可或缺的一部分。在这个数字化时代,博物馆也紧跟时代潮流,将传统的实体博物馆与现代科技相结合,诞生了一种全新的博物馆形式——3D线上博物馆。这种新型博物馆凭借其独特的魅力&…

RT_Thread 调试笔记:串口打印、MSH控制台 相关

说明:记录日常使用 RT_Thread 开发时做的笔记。 持续更新中,欢迎收藏。 1.打印相关 1.打印宏定义,可以打印打印所在文件,函数,行数。 #define PRINT_TRACE() printf("-------%s:%s:%d------\r\n", __FIL…

宏电股份5G RedCap终端产品助力深圳极速先锋城市建设

12月26日,“全城全网,先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行,宏电股份携一系列5G RedCap终端产品应邀参与创新发布会,来自全国5G生态圈的各界嘉宾、专家学者济济一堂,共探信息化数字化创新…

GitHub 一周热点汇总 第4期 (2024/01/01-01/06)

GitHub一周热点汇总第四期 (2023/12/24-12/30),梳理每周热门的GitHub项目,了解热点技术趋势,掌握前沿科技方向,发掘更多商机。2024年到了,希望所有的朋友们都能万事顺遂。 说明一下,有时候本周的热点项目会…

蟹目标检测数据集VOC格式400张

蟹,一种独特的海洋生物,以其强壮的身体和独特的生活习性而闻名。 蟹的身体宽厚,有一对锐利的大钳子,这使得它们在寻找食物和保护自己时非常有力。蟹的外观颜色多样,有绿色、蓝色、棕色和红色等,这使得它们在…

软件工程概论------文件管理

目录 1.文件的相关概念 2.文件目录 3.位示图 4.索引文件 5.例题 1.文件的相关概念 文件:具有符号名的、在逻辑上具有完整意义的一组相关信息项的集合。 逻辑结构:有结构的记录式文件、无结构的流式文件。 物理结构: 连续结构、链接结构、索引结构、多个物理块的索引表。 …

解决ChatGPT4.0无法上传文件

问题描述 ChatGPT4.0:上传文件时出错 解决方案: 仔细检查文件的编码格式,他似乎目前只能接受utf-8的编码,所以把文件的编码改为UTF-8即可成功上传