7.4 责任链模式(Chain of Responsibility pattern)

一. 定义

在现实生活中,一个事件需要经过多个对象处理是很常见的场景,例如:采购审批流程,请假流程等; 公司员工请假,可批假的领导有部门负责人,副总经理,总经理等,但每个领导批准的天数不同,员工必须根据请假天数去找不同的领导签名,员工必须记住每个领导的职务与姓名,这增加了难度;

责任链模式(Chain of Responsibility pattern)

  1. 属于行为型模式;目的是避免请求的发送者 与 多个请求处理者耦合在一起, 实现了请求发送者和请求处理者的解耦;
  2. 该模式为请求创建了一个接收者对象的链,当发生请求时,可将请求沿该链条传递,直到有对象处理它为止,
  3. 通常每个接收者都包含对下一个接收者的引用,如果一个对象不能处理该请求,则把相同的请求传给下一个接收者,以此类推;
  4. 在责任链模式中,客户只需将请求发送到责任链上即可,无须关心请求的处理细节 和 请求的传递过程,请求会会自动进行传统;

二. 特点

责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;

是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。

1. 优点

   1) 降低了对象间的耦合度,每个对象无需知道链的结构和保存所有候选处理者的引用,仅需维护下一处理者地址,避免了众多if语句;

   2) 增强了系统的可扩展性,可根据需要增加新的请求处理类,满足开闭原则;

   3) 增加了给对象指派职责的灵活性,当工作流程发送变化时,可动态改变链内的成员或调度它们的次序,也可动态增加或删除责任;

   4) 责任分担,每个类只需处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则;

2. 缺点

     1) 不能保证每个请求一定被处理,由于请求没有明确的接收者,故不能保证它一定被处理,该请求可能传到链的末端都得不到处理;

     2) 较长的责任链,请求的处理可能涉及多个处理对象,使系统性能受到影响,因此需要控制链中最大节点数量,

         一般在Handler中设置一个最大节点数量,在setNext()方法中判断是否已超过阈值,超过则不允许该链建立,

         避免出现超长链无意识的破坏系统性能;

     3) 责任链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于责任链的错误设置导致系统出错,如:造成循环调用;

三. 应用场景

  1. 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定;

  2. 可动态指定一组对象处理请求,或添加新的处理者;

  3. 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求;

四. 模式的结构

0. 责任链实现原理

1) 责任链由若干个处理类拼接而成,每个处理类都有两个函数:

     setNext(Handler)用于设置当前处理类的下一跳地址; processRequest(Request)用于处理请求;

2) 定义完处理类后,客户端创建所有处理类的对象,然后通过每个对象的setNext(Handler)函数设置每个对象的下一跳地址。

    之后执行对象的processRequest(request)函数,使整条链开始工作,request会以此传递下去,直到某个处理类能处理该请求为止。

1.责任链模式结构图

2.责任链模式的角色及职责

  1. Handler(抽象处理者): 定义一个处理请求的接口,包含抽象处理方法 和 一个后继连接;

  2. ConcreteHandler(具体处理者): 实现处理方法,判断能否处理本次请求,若可处理则处理请求,否则将该请求转给其后继者处理;

  3. Client(客户类): 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节 和 请求的传递过程;

五. 模式的实现

0. 项目需求

学校OA系统的采购审批项目,请设计程序完成采购审批项目:

1)采购元采购教学器材

2)如果金额小于等于 5000, 由教学主任审批;x:[0,5000]

3)如果金额小于等于10000,由院长审批; x:(5000,10000]

4)如果金额小于等于30000,由副校长审批;x:(10000,30000]

5)如果金额超过30000以上, 由校长审批; x:(30000,+∞)

1. 传统方案解决

传统方案解决OA系统审批问题分析

1>传统方案是: 接收到一个采购请求后,根据采购金额来调用对应的Approver(审批人)完成审批;

2>问题分析: 客户端这里会使用到 分支判断(比如 switch) 来对不同的采购请求处理,这样就存在如下问题

1)如果各个级别的人员审批金额发生变化,在客户端也需要跟进变化;

2)客户端必须明确的知道 有多少个审批级别 和 访问;

3)这样 对一个采购请求进行处理 和 Approver(审批人) 就存在强耦合关系,不利于代码的扩展 和 维护;

2. 责任链模式实现

1> 实例结构图

2> 相关代码实现

object Client {
    @JvmStatic
    fun main(args: Array<String>) {
        //创建一个采购审批请求
        val purchaseRequest = PurchaseRequest(1, 8000f, 1)
        //创建相关审批人
        val departmentApprover = DepartmentApprover("张主任")
        val collegeApprover = CollegeApprover("李院长")
        val viceSchoolMasterApprover = ViceSchoolMasterApprover("王副校长")
        val schoolMasterApprover = SchoolMasterApprover("钱校长")
        //将各个审批级别的下一个审批者设置好(指定从第一个开始处理 或 确定 有处理人构成环状处理)
        departmentApprover.approver = collegeApprover
        collegeApprover.approver = viceSchoolMasterApprover
        viceSchoolMasterApprover.approver = schoolMasterApprover
//        schoolMasterApprover.approver = departmentApprover

        //从第一个开始处理
        departmentApprover.processRequest(purchaseRequest)
    }
}
/**
 * 采购审批请求
 * type 请求类型
 * price 请求金额
 * id 请求编号
 */
class PurchaseRequest(var type:Int=0,var price:Float=0.0f,var id:Long=0)
/**
 * 审批人: Handler
 */
abstract class Approver(var name:String) {
    lateinit var approver: Approver //下一个处理者
    //设置下一个处理者
    fun setNextApprover(nextApprover: Approver){
        approver=nextApprover
    }

    //处理审批请求的方法,得到一个请求,处理是子类完成,因此该方法设为抽象方法
    abstract fun processRequest(request:PurchaseRequest)
}
/**
 * 系主任审批 ConcreteHandler1
 */
class DepartmentApprover(name:String) : Approver(name){
    override fun processRequest(request: PurchaseRequest) {
        if (request.price <= 5000) {
            println("请求编号 id= ${request.id} 被 $name 处理")
        } else {
            approver.processRequest(request)
        }
    }
}
/**
 * 院长审批 ConcreteHandler2
 */
class CollegeApprover(name:String) : Approver(name){
    override fun processRequest(request: PurchaseRequest) {
        val price = request.price
        if (price > 5000 && price<=10000) {
            println("请求编号 id= ${request.id} 被 $name 处理")
        } else {
            approver.processRequest(request)
        }
    }
}
/**
 * 副校长审批 ConcreteHandler3
 */
class ViceSchoolMasterApprover(name:String) : Approver(name){
    override fun processRequest(request: PurchaseRequest) {
        val price = request.price
        if (price > 10000 && price<=30000) {
            println("请求编号 id= ${request.id} 被 $name 处理")
        } else {
            approver.processRequest(request)
        }
    }
}
/**
 * 校长审批 ConcreteHandler4
 */
class SchoolMasterApprover(name:String) : Approver(name){
    override fun processRequest(request: PurchaseRequest) {
        if (request.price > 30000) {
            println("请求编号 id= ${request.id} 被 $name 处理")
        } else {
            approver.processRequest(request)
        }
    }
}

程序运行结果

请求编号 id= 1 被 李院长 处理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值