一,简介
责任链模式是行为型模式的一种,它的原始定义是:避免将一个请求发送者与接收者耦合在一起,让多个对象都有机会处理请求,将接收请求的对象连城一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
在责任链模式中,多个处理器(也就是定义中说的接收对象)依次处理同一个请求, 一个请求先经过A处理器处理,然后交由B处理器处理,B处理器处理完在交给C处理器,依此类推,链条上的每个处理器各自承担各自的处理职责,所以叫做职责链模式。
二、原理![](https://i-blog.csdnimg.cn/blog_migrate/9b0e9c5b58b9f83cec26052cc6784ba3.png)
职责链模式由以下几种角色组成
①抽象处理者:包含一个抽象处理方法,保存一个next的抽象处理者成员变量
②具体实现:实现抽象处理者。
③客户端:创建处理链
三、实现
结构实现
1)请求数据封装类
/**
* 请求数据类
*/
public class RequestData {
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
2)抽象处理者类
/**
* 抽象处理类
*/
public abstract class Handler {
//后继处理者
protected Handler next;
//处理方法
public abstract void process(RequestData requestData);
}
3)具体处理者
/**
* 具体处理者
*/
class HandlerA extends Handler{
@Override
public void process(RequestData requestData) {
System.out.println("HandlerA 处理数据:"+requestData);
requestData.setData(requestData.getData().replace("A",""));
//判断是否有后继处理者
if (next!=null){
next.process(requestData);
}else {
System.out.println("处理结束");
}
}
}
class HandlerB extends Handler{
@Override
public void process(RequestData requestData) {
System.out.println("HandlerB 处理数据:"+requestData);
requestData.setData(requestData.getData().replace("B",""));
//判断是否有后继处理者
if (next!=null){
next.process(requestData);
}else {
System.out.println("处理结束");
}
}
}
4)客户端类
class Client{
public static void main(String[] args) {
//创建请求数据
RequestData data = new RequestData();
data.setData("ABC");
//创建处理器
Handler a = new HandlerA();
Handler b = new HandlerB();
Handler c = new HandlerC();
//设置链条
a.setNext(b);
b.setNext(c);
//执行方法
a.process(data);
/**
* HandlerA 处理数据:RequestData{data='ABC'}
* HandlerB 处理数据:RequestData{data='BC'}
* HandlerC 处理数据:RequestData{data='C'}
* 处理结束
*/
}
}
场景实现
接下来我们模拟一个有双11期间业务系统审批的流程,临近双十一公司会有陆续有一些新的需求上线,为了保证线上系统的稳定,我们对上线的审批流畅做了严格的控制,审批的过程会有不同级别的负责人加入进行审批(平常系统上线只需三级负责人审批即可,双十一前后需要二级或一级审核人参与审批),接下来我们就使用职责链模式来设计一下此功能。
1)不使用设计模式
/**
* 审核信息
*/
public class AuthInfo {
//审核编码
private String code;
//审核信息
private String info="";
public AuthInfo(String code, String info) {
this.code = code;
this.info = info;
}
}
/**
* 处理信息抽象接口
*/
public interface Approval {
void processAuthInfo(AuthInfo authInfo);
}
class ThreeApproval implements Approval{
@Override
public void processAuthInfo(AuthInfo authInfo) {
System.out.println("三级审批处理信息");
}
}
class TwoApproval implements Approval{
@Override
public void processAuthInfo(AuthInfo authInfo) {
System.out.println("二级审批处理信息");
}
}
class OneApproval implements Approval{
@Override
public void processAuthInfo(AuthInfo authInfo) {
System.out.println("一级审批处理信息");
}
}
public class Client1 {
public static void main(String[] args) {
AuthInfo authInfo = new AuthInfo("110", "123");
System.out.println("双十一之前");
ThreeApproval threeApproval = new ThreeApproval();
threeApproval.processAuthInfo(authInfo);
System.out.println("双十一时");
TwoApproval twoApproval = new TwoApproval();
threeApproval.processAuthInfo(authInfo);
OneApproval oneApproval = new OneApproval();
oneApproval.processAuthInfo(authInfo);
/**
* 双十一之前
* 三级审批处理信息
* 双十一时
* 三级审批处理信息
* 一级审批处理信息
*/
}
}
通过以上实例我们可以看出,我们要完成整个流程,每一个节点都需要我们手动的调用算法,具体的调用由客户端直接去操作,而有时候调用者不需要关注其他节点的信息,只需要将任务交由一个节点去处理,具体后续节点的处理我并不关心 ,那么我们该如何改造呢?
2)使用设计模式
/**
* 审批处理器抽象类
*/
public abstract class Approve {
//后继处理者
protected Approve next;
public void setNext(Approve next) {
this.next = next;
}
//后继处理方法
abstract void processApprove(AuthInfo authInfo);
}
/**
* 三级审批
*/
class ThreeApprove extends Approve{
@Override
void processApprove(AuthInfo authInfo) {
authInfo.setInfo("三级审批完成");
if (next!=null){
System.out.println("三级审批完成,开始处理二级");
next.processApprove(authInfo);
}else {
System.out.println("处理结束");
}
}
}
/**
* 二级审批
*/
class TwoApprove extends Approve{
@Override
void processApprove(AuthInfo authInfo) {
authInfo.setInfo("二级审批完成");
if (next!=null){
System.out.println("二级审批完成,开始处理一级");
next.processApprove(authInfo);
}else {
System.out.println("处理结束");
}
}
}
/**
* 一级审批
*/
class OneApprove extends Approve{
@Override
void processApprove(AuthInfo authInfo) {
authInfo.setInfo("一级审批完成");
if (next!=null){
next.processApprove(authInfo);
}else {
System.out.println("处理结束");
}
}
}
class Client2{
public static void main(String[] args) {
AuthInfo authInfo = new AuthInfo("1", "");
//模拟双十一:假设双十一需要三级审批
//创建处理器
ThreeApprove three = new ThreeApprove();
TwoApprove two = new TwoApprove();
OneApprove one = new OneApprove();
//设置链路
three.setNext(two);
two.setNext(one);
//开始调用
three.processApprove(authInfo);
/**
* 三级审批完成,开始处理二级
* 二级审批完成,开始处理一级
* 处理结束
*/
}
}
通过上述实例我们很容易发现,处理方式较不使用设计模式更加容易维护,调用者只需要关注第一层处理器即可,其余层次不需要调用,如果后续增加了新的链路我们只需要挪动next就可以,无需改动代码,符合开闭原则,使代码可读性加强,更容易维护。
四、总结
优点
①降低了对象之间的耦合度:该模式降低了请求者和发送者的耦合度
②增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则
③增强了对象指派职责的灵活性:当工作流程发生变化,可以动态的改变链内的成员或者修改它们的次序,也可动态的新增或者删除责任
④责任链简化了对象之间的链接:一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的应用,这避免了众多的if-else语句。
⑤责任分担 :每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点
①不能保证每个请求一定被处理,由于一个请求没有明确的接收者,所以不能保证它有一定会被处理,该请求可能一直传到末端都得不到处理。
②对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能受到一定的影响。
③职责链的合理性靠客户端来保证,增加了客户端的复杂性,可能会由于职责链错误而导致系统出错,如可能会造成循环调用。
使用场景
责任链模式场景的使用场景有以下几种情况
①在运行时需要使用多个关联对象来处理同一请求,比如:请假流程,员工入职流程等。
②不想让使用者知道具体的逻辑时,比如做权限校验或拦截器
③需要动态的更换处理对象时,比如:工单处理系统
④职责链模式常常被用在框架中,比如过滤器,拦截器等等