职责链模式

2023-11-07

职责链模式概述

职责链模式解决的问题

案例 : 一个贷款审批案例,假设贷款额度小于5万时由客户负责人审核放款,当贷款额度大于5万小于10万时由项目经理负责审批,当贷款额度大于10万小于20万时由审核团队来审批
问题 : 由谁来审批是通过贷款金额大小来决定的,在传统模式中,通常会使用 if - else等相关流程判断语句,来判断金额大小,获取到审批的负责人,会出现大量的条件转移语句,影响代码可读性,假设后续更改了审批规则,则需要更改这个的代码违反ocp原则

角色分析

  • 抽象处理者 Handler : 定义了处理请求的接口,同时持有另外一个处理者
  • 具体处理者 ConcreteHandler : 一般存在多个,实现抽象处理者,根据自己的责任重写实现处理的功能方法,可以将多个具体处理者看为是不同级别的责任人,每一个具体处理者都会持有一个下一级的具体处理者,当前请求这个处理者若可以处理则调用自己的处理方法进行处理, 当判断无法处理时,会将请求交个持有的下一级具体处理者进行处理,依次类推到最后抛出异常等
  • 注意点: 明确不同级别处理者持有的下一个级别的处理者,在接收请求前创建设置完成,有接收请求的处理者内部自行判断是否能够处理
  • 自己理解: 就是创建不同职责的类,每一个职责类持有下一个职责类对象,实现功能的方法根据职责的不同定义在职责类中,在职责类中只判断当前职责类是否能处理,如果能处理则处理,否则交给持有的下一级别的职责类对象进行处理,形成一个环

职责链模式优点

  • 职责链模式的最主要功能就是:动态组合,请求者和接受者解耦。
  • 请求者和接受者松散耦合:请求者不需要知道接受者,也不需要知道如何处理。每个职责对象只负责自己的职责范围,其他的交给后继者。各个组件间完全解耦。
  • 动态组合职责:职责链模式会把功能分散到单独的职责对象中,然后在使用时动态的组合形成链,从而可以灵活的分配职责对象,也可以灵活的添加改变对象职责。

代码示例

上面的审批贷款案例通过职责链模式实现

  1. 创建抽象处理者
abstract  class Approver{
    private Approver approver; //下一个等级的处理者
    private String name; //处理者姓名

    public Approver(String name){
        this.name = name;
    }

    //获取下一个级别的处理者
    public Approver getApprover() {
        return approver;
    }
    //设置下一个级别的处理者
    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    //处理审批请求的抽象方法,有具体处理者根据
    //自己的责任进行具体实现,传递请求对象,通
    //过请求对象可以获取到用来判断是否有职责处理的数据
    public abstract void processRequest(PurchaseRequest purchaseRequest);

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 创建具体处理者,此处有三个"客户负责人",“项目经理”,“审核会议”,具体处理者继承抽象处理者,持有下一个级别的处理者,根据自己的责任重写处理方法,在方法中判断当前处理者是否能处理这个审批请求,当当前处理者无法处理时交由持有的下一个处理者进行处理
    客户负责人
class Principal extends Approver{

    public Principal(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        //当小于等于5万时,有当前"客户负责人"级别进行处理
        if(purchaseRequest.getPrice() <= 5){
            System.out.println("客户贷款金额为:"+purchaseRequest.getPrice()
                    +"万,由客户负责人:"+this.getName()+"负责审批处理");
        }else {
           //否则交由持有的下一个级别进行处理
            this.getApprover().processRequest(purchaseRequest);
        }
    }
}

项目经理

//项目经理处理者
class Manager extends Approver{

    public Manager(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() <= 10){
            System.out.println("客户贷款金额为:"+purchaseRequest.getPrice()
                    +"万,由项目经理:"+this.getName()+"负责审批处理");
        }else {

            this.getApprover().processRequest(purchaseRequest);
        }
    }
}

审核会议(最终处理者)

class Conference extends Approver{

    public Conference(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() <= 20){
            System.out.println("客户贷款金额为:"+purchaseRequest.getPrice()
                    +"万,由审核会议:"+this.getName()+"负责审批处理");
        }else {
            //最终级别处理者,当还是处理不了时抛出异常
            System.out.println("客户贷款金额为:"+purchaseRequest.getPrice()
                    +"万,金额太大抛出异常");
            //也可以设置交由下一个处理者处理
            //this.getApprover().processRequest(purchaseRequest);
        }
    }
}
  1. 调用测试,注意点,将请求交由具体处理者,在具体处理者中判断是否能够处理,在接收请求以前,就需要创建出所有处理者,并设置好处理者中持有的指定下个级别处理者
	public static void main(String[] args) {
        //注意点,在接收请求进行处理时,要设置好
        //每个处理者持有的下一个处理者
        Approver principal = new Principal("负责人小明");
        Approver manager = new Manager("项目经理小红");
        Approver conference = new Conference("贷款会议小组");

        //设置负责人级别,持有项目经理级别,当负责人无法处理时,交由项目经理处理
        principal.setApprover(manager);
        //设置项目经理级别,持有会议级别,当项目经理处理不了时,交由审核会议处理
        manager.setApprover(conference);
        //审核会议为最终级别,可以不设置,也可以设置形成闭环
        //conference.setApprover(principal);

        //创建请求对象,客户端请求
        PurchaseRequest purchaseRequest = new PurchaseRequest("贷款请求",21);
		
		//通过处理者处理,
        principal.processRequest(purchaseRequest);
    }

源码中的职责链模式使用案例

在 Spring 框架中,或权限框架中经常见到职责链模式,拦截器,权限校验等功能都是通过责任链来实现的,查看 javax.servlet .Filter 过滤器,该接口中有一个doFilter()方法,在我们实现过滤器时,通常要继承Filter接口重写doFilter()方法,此处的Filter就相当于一个抽象处理者,而具继承该接口实现子类就是具体处理者,doFilter()方法就是实际处理方法

业务与设计模式落地案例

  1. 职责链设计模式适用于有多个对象处理同一个请求的场景,这些对象可以按照顺序构成一条责任链,每个对象处理请求的方式不同,但是都可以根据请求的内容来判断是否自己需要处理。如果需要处理,则自己负责处理请求;否则就将请求传递给责任链中的下一个对象
  2. 网上购物平台的订单支付功能通过职责链设计模式实现
  3. 定义支付处理器接口,该接口包含了处理支付请求的方法
public interface PaymentHandler {
	//用于判断该处理器是否可以处理当前支付请求
    boolean canHandle(PaymentRequest request);
    //处理具体支付请求
    void handle(PaymentRequest request);
}
  1. 定义具体的支付处理器实现类,假设有3个处理器
@Component
public class AlipayHandler implements PaymentHandler {
    @Override
    public boolean canHandle(PaymentRequest request) {
        // 根据请求信息判断是否能够处理
        return "alipay".equals(request.getPaymentType());
    }

    @Override
    public void handle(PaymentRequest request) {
        // 处理支付请求
        System.out.println("使用支付宝处理支付请求:" + request.getAmount());
    }
}

@Component
public class WechatPayHandler implements PaymentHandler {
    @Override
    public boolean canHandle(PaymentRequest request) {
        // 根据请求信息判断是否能够处理
        return "wechatpay".equals(request.getPaymentType());
    }

    @Override
    public void handle(PaymentRequest request) {
        // 处理支付请求
        System.out.println("使用微信支付处理支付请求:" + request.getAmount());
    }
}

@Component
public class CreditCardHandler implements PaymentHandler {
    @Override
    public boolean canHandle(PaymentRequest request) {
        // 根据请求信息判断是否能够处理
        return "creditcard".equals(request.getPaymentType()) && request.getAmount() <= 1000;
    }

    @Override
    public void handle(PaymentRequest request) {
        // 处理支付请求
        System.out.println("使用信用卡处理支付请求:" + request.getAmount());
    }
}
  1. 定义PaymentController控制器,用于接收来自客户端的支付请求,并调用支付处理器处理请求
@RestController
@RequestMapping("/payment")
public class PaymentController {
    private final List<PaymentHandler> handlers;

    public PaymentController(List<PaymentHandler> handlers) {
        this.handlers = handlers;
    }

    @PostMapping("/")
    public String pay(@RequestBody PaymentRequest request) {
    	//循环遍历所有处理器,调用canHandle方法来判断是否能够处理请求
    	//如果找到匹配的处理器,调用handle方法来处理请求
        for (PaymentHandler handler : handlers) {
            if (handler.canHandle(request)) {
                handler.handle(request);
                return "success";
            }
        }
        return "no suitable handler found";
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

职责链模式 的相关文章

随机推荐

  • 菜鸟电子面单打印

    一 首先开通电子面单服务 然后自己编辑一个模板 地址 https cloudprint cainiao com print 提示 这里不再详细说明 网上随便找了一个模板地址 如果不会 下面我会提供一个 没有关系 二 需要一台打印机 我的打印
  • 使用 Python 的ChatGPT API 的简单指南

    OpenAI 刚刚发布了 ChatGPT API 这是一个调用 GPT 3 5 Turbo 的 API 与 ChatGPT 产品中使用的模型相同 对于那些已经熟悉 Python 中的 OpenAI API 的人来说 学习如何使用 ChatG
  • Git安装和配置

    Git Gitee 官网安装配置教程 https gitee com help articles 4104 本文是以官网教程为基础而展开的实践笔记 初学者可以以本文为引入 但建议最终以官方文档为最终深入学习的参考 一 下载和安装Git 1
  • 关于scsi锁的故事

    最后更新2021 11 01 一不小心 已经11月了 冬天围着火锅烤串喝啤酒的好日子 scsi锁的出发点很正确 谁用谁锁 用后开锁 目的是避免并行访问的时候有其它不知情的访问变更了数据 更狠毒的是变更了meta数据 整体存储数据结构就乱掉了
  • 微信小程序卖货收费吗?企业公司商家要知道的

    有些小伙伴想做一个微信小程序卖货 就会咨询相关问题 例如微信小程序卖货收费吗 那么下面就和大家探探下这个问题 答案是 收费的 微信小程序卖货收费主要大致有三个地方 一 认证费用 在申请微信小程序账号的时候 要给小程序账号做认证 费用是300
  • 《TensorFlow深度学习》笔记

    import tensorflow as tf from tensorflow import keras from tensorflow keras import datasets import numpy as np import mat
  • phpstudy的mysql服务启动又停止

    前面装了一个MySQL 试了看到的各种方法都不行 试了一下phpmyadmin phpmyadmin通过点击上面的数据库工具打开 发现可以了
  • mongodb常用操作

    只显示某一字段 db extra third 2 2 find name 1 删除字段 db extra third 2 2 remove name null 导出某一个collection usr local app mongodb bi
  • linux永久自动挂载

    给sdb先分两个区 fdisk dev sdb vi etc fstab 永久挂载文件 第1列 挂载设备 想挂谁就写谁 第2列 挂载点 boot 想要永久挂载到根下d1或d2 在这里就写根下d1或d2 第3列 文件系统类型 xfs 格式化成
  • Vue3实现将页面转成PDF并下载或直接打印

    步骤一 安装依赖包 npm i html2canvas npm i jspdf 步骤二 在utils文件夹下新建htmlToPdf js文件 页面导出为pdf格式 import html2Canvas from html2canvas im
  • HASH函数的特点及其应用

    HASH函数必须具备两个基本特征 单向性 和 碰撞约束 单向性是指其的操作方向的不可逆性 在HASH函数中是指 只能从输入推导出输出 而不能从输出计算出输入 碰撞约束是指 不能找到一个输入使其输出结果等于一个已知的输出结果 或者 不能同时找
  • nmap常用指令

    一 Nmap扫描端口常用指令 1 虚拟机的扫描 arp scan l 2 TCP Connect 扫描 通过试图与主机相应的TCP端口建立一个完整的TCP连接 从而判断主机端口的开放信息 nmap sT 域名 IP地址 结果 列出开放的端口
  • 如何在Linux环境下跑Wacom的板子

    文章目录 简介 也许你什么都不需要做 安装Wacom驱动 配置Wacom设备 简介 首先 在Linux环境下使用数位板或者数位屏也算是比较小众的一种需求了 但放在大环境下 各大电影公司例如皮克斯 梦工厂都有极其强大的后期制作能力 甚至强大到
  • java在源目录下根据文件名找到文件并返回绝对路径(递归)

    import java io File public class RecursionDemo2 public static void main String args searchFiles new File D YoudaoDict ex
  • hive -e 和hive -f 的注意点 (//和////)

    原谅我张嘴可能就想骂人 当然跟别人无关 想骂的是自己太年轻 也顺便记录下这个注意点 菜鸟一只 多多见谅 大家都知道 hive f 后面指定的是一个文件 然后文件里面直接写sql 就可以运行hive的sql hive e 后面是直接用双引号拼
  • 如何运用MATLAB实现K-MEANS聚类分析

    由于自己最近在学习聚类分析 也算是一个入门 相当于将自己这段时间的学习成果进行一个总结 分享给更多打算学习聚类分析或者需要用到聚类分析的同学们 在了解K MEANS聚类分析之前 我们首先明确聚类的含义 聚类是将数据分类到不同的类或者簇这样的
  • Springboot 后端配置流程

    概述 分三步 一 从github克隆项目master分支来 git操作步骤 目录 1 配置用户名和邮箱 2 初始化 3 设置仓库地址 4 拉取代码 5 设置保存账号密码时间 6 查看状态 sudo git config global use
  • python中find函数的使用方法_Python re 模块findall() 函数返回值展现方式解析

    findall 函数 在字符串中找到正则表达式所匹配的所有子串 并返回一个列表 如果没有找到匹配的 则返回空列表 注意 match 和 search 是匹配一次 findall 匹配所有 match 和 search 的区别也很大 可以自行
  • 自媒体必备的4个文案网站,每一个都很实用,赶紧收藏

    1 文案狗 在这里 谐音梗 不用担心扣钱 很多广告词 slogan都离不开它 如果实在想不到合适的词 可以在这里搜索 有了这么多的词汇灵感 再也不担心写不出吸睛的广告文案了 是广告人非常喜欢的文案网站 只要输入关键字或者词语 就能生成各种谐
  • 职责链模式

    职责链模式 职责链模式概述 职责链模式解决的问题 角色分析 职责链模式优点 代码示例 源码中的职责链模式使用案例 业务与设计模式落地案例 职责链模式概述 职责链模式解决的问题 案例 一个贷款审批案例 假设贷款额度小于5万时由客户负责人审核放