在现实生活中,一个事件需要经过多个对象处理是很常见的场景,例如:采购审批流程,请假流程等; 公司员工请假,可批假的领导有部门负责人,副总经理,总经理等,但每个领导批准的天数不同,员工必须根据请假天数去找不同的领导签名,员工必须记住每个领导的职务与姓名,这增加了难度;
责任链模式(Chain of Responsibility pattern)
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;
是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
1) 降低了对象间的耦合度,每个对象无需知道链的结构和保存所有候选处理者的引用,仅需维护下一处理者地址,避免了众多if语句;
2) 增强了系统的可扩展性,可根据需要增加新的请求处理类,满足开闭原则;
3) 增加了给对象指派职责的灵活性,当工作流程发送变化时,可动态改变链内的成员或调度它们的次序,也可动态增加或删除责任;
4) 责任分担,每个类只需处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则;
1) 不能保证每个请求一定被处理,由于请求没有明确的接收者,故不能保证它一定被处理,该请求可能传到链的末端都得不到处理;
2) 较长的责任链,请求的处理可能涉及多个处理对象,使系统性能受到影响,因此需要控制链中最大节点数量,
一般在Handler中设置一个最大节点数量,在setNext()方法中判断是否已超过阈值,超过则不允许该链建立,
避免出现超长链无意识的破坏系统性能;
3) 责任链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于责任链的错误设置导致系统出错,如:造成循环调用;
多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定;
可动态指定一组对象处理请求,或添加新的处理者;
需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求;
1) 责任链由若干个处理类拼接而成,每个处理类都有两个函数:
setNext(Handler)用于设置当前处理类的下一跳地址; processRequest(Request)用于处理请求;
2) 定义完处理类后,客户端创建所有处理类的对象,然后通过每个对象的setNext(Handler)函数设置每个对象的下一跳地址。
之后执行对象的processRequest(request)函数,使整条链开始工作,request会以此传递下去,直到某个处理类能处理该请求为止。
Handler(抽象处理者): 定义一个处理请求的接口,包含抽象处理方法 和 一个后继连接;
ConcreteHandler(具体处理者): 实现处理方法,判断能否处理本次请求,若可处理则处理请求,否则将该请求转给其后继者处理;
Client(客户类): 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节 和 请求的传递过程;
学校OA系统的采购审批项目,请设计程序完成采购审批项目:
1)采购元采购教学器材
2)如果金额小于等于 5000, 由教学主任审批;x:[0,5000]
3)如果金额小于等于10000,由院长审批; x:(5000,10000]
4)如果金额小于等于30000,由副校长审批;x:(10000,30000]
5)如果金额超过30000以上, 由校长审批; x:(30000,+∞)
传统方案解决OA系统审批问题分析
1>传统方案是: 接收到一个采购请求后,根据采购金额来调用对应的Approver(审批人)完成审批;
2>问题分析: 客户端这里会使用到 分支判断(比如 switch) 来对不同的采购请求处理,这样就存在如下问题
1)如果各个级别的人员审批金额发生变化,在客户端也需要跟进变化;
2)客户端必须明确的知道 有多少个审批级别 和 访问;
3)这样 对一个采购请求进行处理 和 Approver(审批人) 就存在强耦合关系,不利于代码的扩展 和 维护;
1> 实例结构图
2> 相关代码实现
object Client {
@JvmStatic
fun main(args: Array) {
//创建一个采购审批请求
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 被 李院长 处理