责任链模式(Chain of Responsibility Pattern)
职责链模式
意图
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系
将这些对象链接成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
责任链模式中,每一个对象经过持有对下家的引用而连接起来,造成一条链条,串联起来多个处理对象。
在责任链模式中,请求在链上进行传递,直到链上的某一个对象决定处理此请求。
发出这个请求的客户端程序并不知道究竟是哪个对象具体的处理了请求
这使得系统能够在不影响客户端的状况下,动态的从新组织链和增长责任
好比类加载机制中的双亲委派模型,类加载器含有父 类加载器的引用,造成了一个处理链
(不过类加载机制的具体行为与责任链有出入,会一直委派到最顶级类加载,而不会在中间进行处理而后返回)
解析
责任链模式是一种很常见的场景
好比请假,不少公司会根据请假的缘由以及请假的时长,将会有不一样的审批人
好比采购,对于采购金额的不一样,可能须要不一样的审批人
思考下请假的过程,可能你经历过有两种形式:
形式一:
第一步你写好请假条;
第二步你拿给人事,人事说找部门主管签字
第三步你拿请假条给部门主管,部门主管发现请假三天,而后告诉你,一天以上的假期须要老板审批
第四步你拿请假条给老板审批
形式二:
第一步
你写好请假条交给人事;(人事拿给部门主管,部门主管看状况,若是批不了拿给老板审批)
第二步等待审批;
可能的两种流程就是上面这样子的,请假的流程通常就这样子了,总共有几级审批,这几级审批都有谁负责,也不会轻易的变化
再看一个采购审批的例子
示例
以采购为例演示审批流程
抽象处理人角色 处理人拥有姓名属性,另外定义了抽象的操做方法
package nonechainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
public abstract void operation();
}
具体的处理
人角色 DepartmentManager和Boss
package nonechainresponsibility;
public class DepartmentManager extends Handler {
public DepartmentManager(String name){
super(name);
}
@Override
public void operation() {
System.out.println("DepartmentManager process..name: "+this.name);
}
}
package nonechainresponsibility;
public class Boss extends Handler {
public Boss(String name) {
super(name);
}
@Override
public void operation() {
System.out.println("Boss process..name: " + this.name);
}
}
测试代码以下,流程很简单:
若是是金额小于1000元,由部门经理DepartmentManager 李四审批
不然,将由老总 Boss 张三 审批
上面的实例中
测试类Test做为客户端,也就是至关于采购员
须要自行判断金额的范围,而后找对应的审批人进行审批
若是说金额从几百到几万到几十万,根据金额分别有十几个主管负责人进行审批呢?那么审批的逻辑将会变得很复杂
也就是内部将会有更多的选择逻辑判断
并且
若是规则变更了呢?你将不得不修改逻辑,进行调整,显然很是的不利于扩展
即便是新增一个级别的审批,仍旧是须要修改代码逻辑
另外,
若是不一样的部门的审批顺序略有差别呢?
如何应对?
上面的这种处理逻辑的根本问题在于:审批的流程固化在代码中了
但是你只是个采购员,你但愿的只是审批单被批准,你其实并不关心究竟是谁审批的,那为何你要关注于这么多的细节呢?
责任链模式就是为了解决这种相似的场景。
一句话归纳责任链模式:“能搞就搞,搞不了给下一我的,请求发起者不关心谁帮我处理”
代码示例
处理人角色新增successor 属性,用于做为下游处理,提供了setSuccessor()方法进行设置
而且对operation方法进行改变,接受参数(Integer price)
package chainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void operation(Integer price);
}
部门处理人角色和老板角色同步作出修改
将判断逻辑移入处处理内部
若是本身不能处理,那么请求下游进行处理(示例比较简单,因此Boss没搞)
package chainresponsibility;
public class DepartmentManager extends Handler {
public DepartmentManager(String name){
super(name);
}
@Override
public void operation(Integer price) {
if(price < 1000){
System.out.println("DepartmentManager process..name: "+this.name);
}else{
successor.operation(price);
}
}
}
package chainresponsibility;
public class Boss extends Handler {
public Boss(String name) {
super(name);
}
@Override
public void operation(Integer price) {
System.out.println("Boss process..name: " + this.name);
}
}
测试代码
package chainresponsibility;
public class Test {
public static void main(String[] args){
/*
* 动态生成链条
* */
Handler DmHandler = new DepartmentManager("李四");
Handler BossHandler = new Boss("张三");
DmHandler.setSuccessor(BossHandler);
/*
* 调用处理链的一个起始端点
* */
DmHandler.operation(600);
DmHandler.operation(6000);
}
}
重构后的代码逻辑没有发生变化---仍旧是处理请求
可是经过引入successor 属性,以及setSuccessor()方法,能够将下游处理者串联起来
拥有了下游的引用,若是处理不了就能够将请求向下传递
由于每一个处理者都须要独立面对请求,因此将逻辑内置,也就是条件以参数的形式传递
经过指向下游处理对象的引用,造成了一条链,每次请求只须要请求开始端点位置的对象便可
若是没法处理,会自动请求下游的对象进行处理,客户端不须要关注
并且,经过引用能够在运行期间动态的组织职责链,好比不一样部门处理层级不同的问题就能够轻易解决
若是增长新的审批层级,只须要新增审批类,而且在建立责任链的时候,将新增的审批类添加进去便可
客户端并不须要发生变更
上面的示例简单的演示了职责链模式的演变过程
简单说就是每一个人职责清晰的独立划分开来,而后一个模块负责组装生成责任链
客户端将请求发送给责任链的起始点便可
结构
抽象处理者角色Handler
定义一个处理请求的接口
Handler角色知道“下一个处理者”是谁,若是本身没法处理请求,他会将请求转发给“下一个处理者”
具体的处理者角色ConcreteHandler
处理请求的具体角色,好比上面示例中的DepartmentManager
客户端角色Client
Client角色向组装好的责任链的第一个ConcreteHandler发起请求
经过责任链模式弱化了请求发起者与请求处理者的联系
对于请求者来讲,责任链上的全部对象就是一个请求处理者,到底具体到哪一个类进行出力,请求者并不关心
不存在“某个请求必需要谁处理”这种明确的指向关系,请求者不清楚
专一于本身的工做
每一个处理业务的对象都更加专一于本身的工做,若是本身没法处理,那么交给其余更专业的人
这样则能保障任务可以快速高效的完成
责任链模式并不建立责任链,由系统的其余部分负责建立
示例为了简单因此在测试主函数中一并建立,应该由系统其余部分进行建立,将责任链的链接逻辑与使用解耦
动态改变职责链
引用是组合的形式,能够在运行时动态的设定
上面说到责任链由系统的其余部分进行建立,他能够动态的完成责任链的建立
分类
责任链模式分为纯粹的责任链模式和不纯粹的责任链模式
纯粹的责任链模式要求责任链中的对象,也就是具体的处理者只能在两个行为中选择一个
也就是要么承担责任,要么责任转交给下家
不容许出现某一个具体的处理者对象承担了一部分责任以后又把责任向下传递。
而一般状况下,咱们的实际使用的责任链模式很难纯粹,基本都会掺杂一些处理逻辑
其实这种命名与否的争论对于使用模式毫无心义,重点在于解决问题
黑猫白猫抓到老鼠就是好猫
总结
若是你的系统中已经存在了一个由多个处理者对象组成的请求处理序列
那么你就能够考虑将这个请求处理转换为责任链模式
若是有多于一个处理者对象会处理一个请求,可是事先却并不知道到底谁来处理
这个处理者对象是动态肯定的,好比新来一个采购员,他还不熟悉公司规则,不肯定到底谁来负责审批他的这个单子
责任链显著的特色就是将请求和处理者进行分离,请求者能够不知道具体是谁处理了请求,将请求与处理进行了解耦,提升了系统的灵活性
具体的处理者可能还与责任链的组成顺序有很大的关系,经过选择某些处理者组成链,以及设置顺序,增长了极大的灵活性
责任链模式全部的请求都经过责任链进行处理,若是链比较长,并且需求老是在后端进行处理,势必会引入一些性能问题
并且,客户端不知道具体谁处理的,你也不知道,环节较多,调试时也会不方便
并且还须要控制节点的数量,
要避免超长链的状况,那样这条链将会变成一种负担,这种会破坏系统的性能
并且还须要注意,若是一个请求从头走到尾是否必定会有对象对他进行处理?
若是没有被处理也多是由于没有正确的配置责任链而致使的
若是连接生成的有问题,好比环形,而且也没有设置次数限制,岂不是死循环?这些问题都须要在运用时考虑到
对于责任链一句话总结:若是一个请求,可能会被多个处理者中的一个处理,考虑责任链模式