【设计模式-4.3】行为型——责任链模式

说明:本文介绍设计模式中行为型设计模式中的,责任链模式;

审批流程

责任链模式属于行为型设计模式,关注于对象的行为。责任链模式非常典型的案例,就是审批流程的实现。如一个报销单的审批流程,根据报销单金额大小,需要不同的职位领导审批,金额越大,审批人的职务越高,如下:

在这里插入图片描述

代码如下:

(Staff,财务专员,审批金额不超过5000)

/**
 * 财务专员
 */
public class Staff {

    private String name;

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

    /**
     * 审批
     * @param amount 金额
     * @return 是否通过
     */
    public boolean approve(double amount) {
        if (amount <= 5000) {
            System.out.println(name + "审批通过");
            return true;
        } else {
            System.out.println("驳回申请。【" + name + "】");
            return false;
        }
    }

    public String getName() {
        return name;
    }
}

(Manager,财务经理,审批金额不超过1w)

/**
 * 财务经理
 */
public class Manager {

    private String name;

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

    /**
     * 审批
     * @param amount 金额
     * @return 是否通过
     */
    public boolean approve(double amount) {
        if (amount <= 10000) {
            System.out.println(name + "审批通过");
            return true;
        } else {
            System.out.println("驳回申请。【" + name + "】");
            return false;
        }
    }

    public String getName() {
        return name;
    }
}

(CFO,财务总监,审批金额不超过10w,否则直接找Boss)

/**
 * 财务总监
 */
public class CFO {

    private String name;

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

    /**
     * 审批
     * @param amount 金额
     * @return 是否通过
     */
    public boolean approve(double amount) {
        if (amount <= 100000) {
            System.out.println(name + "审批通过");
            return true;
        } else {
            System.out.println("驳回申请。【" + name + "】");
            return false;
        }
    }

    public String getName() {
        return name;
    }
}

(Client,客户端,审批金额5000)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        int amount = 8000;

        Staff staff = new Staff("财务专员");
        Manager manager = new Manager("财务经理");
        CFO cfo = new CFO("财务总监");

        if (!staff.approve(amount)) {
            if (!manager.approve(amount)) {
                if (!cfo.approve(amount)) {
                    System.out.println("找Boss");
                }
            }
        }
    }
}

(在财务经理这里审批通过)

在这里插入图片描述

通过上面的代码实现,可以看到客户端有多层的if判断,代码臃肿,不够灵活。

我们可以考虑将审批报销流程的各层人员抽象出来,成一个审批人,然后再在该类中再注入一个审批人为上级审批人。另外,创建一个抽象的审批方法,让其他审核人职务继承这个审批人类,实现其审批方法。方法内判断当前审批金额,该审核人职务不能审核其金额时,交给上级审批人审核。

如下:

(Approver,审批人抽象类,有审批人、下一个审批人,抽象审批方法)

/**
 * 审批人
 */
public abstract class Approver {

    /**
     * 审批人姓名
     */
    protected String name;

    /**
     * 下一个审批人
     */
    protected Approver nextApprover;

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

    /**
     * 设置下一个审批人
     * @param nextApprover
     * @return
     */
    public Approver setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
        return this.nextApprover;
    }

    /**
     * 审批
     * @param amount
     */
    public abstract void approve(int amount);
}

(Staff,财务专员,审批金额不大于5000,否则交给下一位审批人审批)

/**
 * 财务专员
 */
public class Staff extends Approver{

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

    @Override
    public void approve(int amount) {
        if (amount <= 5000) {
            System.out.println("审批通过。【" + name + "】");
        } else {
            System.out.println("金额太大,无法审批,交由上级处理。【" + name + "】");
            this.nextApprover.approve(amount);
        }
    }
}

(Manager,财务经理,审批金额不大于1w,否则交给下一位审批人审批)

/**
 * 财务经理
 */
public class Manager extends Approver{

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

    @Override
    public void approve(int amount) {
        if (amount <= 10000) {
            System.out.println("审批通过。【" + name + "】");
        } else {
            System.out.println("金额太大,无法审批,交由上级处理。【" + name + "】");
            this.nextApprover.approve(amount);
        }
    }
}

(CFO,财务总监,审批金额不大于10w,否则找老板处理)

/**
 * 财务总监
 */
public class CFO extends Approver{

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

    @Override
    public void approve(int amount) {
        if (amount <= 100000) {
            System.out.println("审批通过。【" + name + "】");
        } else {
            System.out.println("金额太大,无法审批,请找老板处理。【" + name + "】");
        }
    }
}

(Client,客户端)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 审批金额
        int amount = 200000;

        // 审批人
        Staff staff = new Staff("财务专员");
        Manager manager = new Manager("财务经理");
        CFO cfo = new CFO("财务总监");

        // 设置下一个审批人
        manager.setNextApprover(cfo);
        staff.setNextApprover(manager);

        // 审批
        staff.approve(amount);
    }
}

执行结果,因为审批金额为20w,需要找老板处理;

在这里插入图片描述

或者使用链式编程,直接用一行代码搞定;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 审批金额
        int amount = 200000;

        new Staff("财务专员").setNextApprover(new Manager("财务经理")).setNextApprover(new CFO("财务总监")).approve(amount);
    }
}

区别就在于使用链式编程,只会执行对应审批人内的if代码块;

在这里插入图片描述

以上是责任链模式的内容,责任链模式是很容易理解的设计模式,和我们日常生活非常紧密。但代码却不容易理解,在审批人对象里面再注入一个审批人对象,不容易想明白。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android CardView基础使用

目录 一、CardView 1.1 导入material库 1.2 属性 二、使用(效果) 2.1 圆角卡片效果 2.2 阴影卡片效果 2.3 背景 2.3.1 设置卡片背景(app:cardBackgroundColor) 2.3.2 内嵌布局&#xff0c;给布局设置背景色 2.4 进阶版 2.4.1 带透明度 2.4.2 无透明度 一、CardView 顾名…

麒麟系统添加环境变量

环境变量添加方法 方法一&#xff1a;用户主目录下的.profile或.bashrc文件&#xff08;推荐&#xff09; 登录到你的用户&#xff08;非root&#xff09;&#xff0c;在终端输入&#xff1a; sudo vim ~/.profile 或者 sudo vim ~/.bashrc 翻到该文件最后&#xff0c…

字符串转换整数

字符串转换整数 描述 : 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 myAtoi(string s) 的算法如下&#xff1a; 读入字符串并丢弃无用的前导空格检查下一个字符&am…

[ 云计算 | AWS 实践 ] 使用 Java 检查指定的密钥是否存在于给定的 Amazon S3 存储桶中

本文收录于【#云计算入门与实践 - AWS】专栏中&#xff0c;收录 AWS 入门与实践相关博文。 本文同步于个人公众号&#xff1a;【云计算洞察】 更多关于云计算技术内容敬请关注&#xff1a;CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文&#xff1a; [ 云计算 | …

【C++】异常处理 ① ( 异常概念引入 | 抛出异常语法 | 捕获异常语法 | 异常捕获流程 | 异常处理代码示例 )

文章目录 一、异常处理1、异常概念引入2、抛出异常语法3、捕获异常语法4、异常捕获流程 二、异常处理代码示例1、错误代码示例 - 抛出异常 / 不捕获异常2、正确代码示例 - 抛出异常 / 捕获异常3、正确代码示例 - 抛出异常 / 捕获异常不处理继续抛出异常 一、异常处理 1、异常概…

nodejs微信小程序+python+PHP问卷调查系统的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

java源码-Java方法的定义和使用详解

1、 方法定义 如果我们想定义一个方法&#xff0c;基本语法如下&#xff1a; 修饰符&#xff1a;方法的修饰符是可选的&#xff0c;用于定义该方法的访问类型&#xff0c;可用的修饰符包括public/private/protected/默认的。 返回值&#xff1a;方法可以有返回值&#xff0c;…

《Junit单元测试》

目录 SpringBoot2.2.0版本之前的单元测试模式 SpringBoot2.2.0版本之后的单元测试模式 SpringBoot2.4以上版本移除了默认对Vintage的依赖 SpringBoot2.2.0版本之前的单元测试模式 SpringBooot 2.2.0 版本开始引入Junit5作为单元测试默认库&#xff0c;之前的版本是使用Junit…

[二分查找双指针]LeetCode881: 救生艇

作者推荐 [二分查找]LeetCode2040:两个有序数组的第 K 小乘积 本文涉及的基础知识点 二分查找算法合集 题目 给定数组 people 。people[i]表示第 i 个人的体重 &#xff0c;船的数量不限&#xff0c;每艘船可以承载的最大重量为 limit。 每艘船最多可同时载两人&#xff0…

Ubuntu系统配置深度学习环境之nvidia显卡驱动和cuda安装

前言 NVIDIA 显卡驱动是为了确保 NVIDIA 显卡能够正确运行而开发的软件。显卡驱动负责与操作系统通信&#xff0c;管理显卡的各种功能&#xff0c;并提供性能优化和兼容性保证。安装适用于特定显卡型号和操作系统版本的最新驱动程序是确保显卡能够正常工作的重要步骤。 CUDA 是…

如何缓解可观察性挑战?

可观察性正在成为当代 DevOps 实践的基石。即使传统上不属于 DevOps 的部门也看到了在可观察性团队的支持下带来的好处。然而&#xff0c;到 2023 年&#xff0c;组织发现采用之路比预期更加崎岖。以下是 DevOps 团队在可观察性方面面临的七个最大挑战以及一些缓解这些挑战的建…

严蔚敏数据结构题集 p18(2.25——2.30)(c语言代码实现)

目录 2.25假设以两个元素依值递增有序排列的线性表A和B分别表示两个集合(即同一表中的元素值各不相同),现要求另辟空间构成一个线性表C,其元素为A和B中元素的交集,且表C中的元素也依值递增有序排列。试对顺序表编写求C的算法。 2.26要求同2.25题。是对单链表编写求C的算法 2.…

Linux socket编程(9):IO复用之poll和epoll详解

在之前的文章中&#xff0c;我们学习了IO复用模型之select原理及例子&#xff0c;但是select有监听描述符个数的限制&#xff0c;而且select的效率并不高&#xff0c;所以这篇文章就来学习效率更高的poll和Linux特有的epoll方法。 文章目录 1 select/poll/epoll对比2 poll2.1 p…

【开源项目】Windows串口通信组件 -- Com.Gitusme.IO.Ports.SerialPort

目录 1、项目介绍 2、组件集成 1&#xff09;下载地址&#xff1a; 2&#xff09;添加项目依赖 3、使用方法 4、GitHub项目地址 1、项目介绍 Com.Gitusme.IO.Ports.SerialPort 是一款 Windows 串口通信组件&#xff0c;基于.Net Core 3.1 开发&#xff0c;支持 Console、Wi…

PostgreSQL有意思的现象:支持不带列的表

1、前言 以前从没有试过建一张表&#xff0c;不带任何列。在PG中却支持这种语法。这是个什么鬼? 最近&#xff0c;把PG源码扒了下&#xff0c;简单浏览了下最近的一些merge。其中有一个fix&#xff1a; eeb0ebad79 ("Fix the initial sync tables with no columns.&qu…

CRM简单小结

思想 对于三层架构&#xff0c;一个模块对应一个controller&#xff0c;controller实际就是Servlet&#xff1b;一张表对应一个domain类对应一个dao接口对应一个mapper文件&#xff1b;service层没有严格规定&#xff0c;如果两张表内容相近&#xff0c;用一个service接口也可以…

【C++练级之路】【Lv.2】类和对象(上)(类的定义,访问限定符,类的作用域,类的实例化,类的对象大小,this指针)

目录 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类的对象大小的计算7.1 类对象的存储方式猜测7.2 如何计算类对象的大小 八、类成员函数的this指针8.1 this指针的引出8.2 this指…

排序算法介绍(二)冒泡排序

0. 简介 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法。它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排…

CentOS7搭建部署NTP服务器

服务端配置&#xff1a; yum install ntp ntpdate -y #下载安装包 修改配置文件&#xff0c;同步阿里的NTP服务器 vim /etc/ntp.conf systemctl start ntpd #启动该服务 ntpq -p #查看是否同步了阿里的NTP 服务端同步成功后&#xff0c;可以去新增…

移除元素、合并两个有序数组(leetcode)

一、移除元素 思路三&#xff1a; while(src<numsSize) 使用一个 while 循环来遍历数组。循环的条件是 src 必须小于 numsSize&#xff0c;以确保不会越界。 if(nums[src]!val) 如果当前 src 指向的元素不等于给定的值 val&#xff0c;则执行以下操作&#xff1a; nums[ds…