责任链模式:Chain of Responsibility
简介
职责链是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推,直到有对象处理它为止(也可能没有),如此使得每个接收者都有机会接收和处理请求。
对于调用者来说,调用者只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链也将请求的发送者和处理者进行了解耦。
场景举例
一个事件需要经过多个对象处理是一个挺常见的场景,譬如客服咨询流程,采购审批流程,请假流程,软件开发中的异常处理流程,多种过滤系统等各种各样的流程,可以考虑使用责任链模式来实现。

比如,你刚为自己的电脑购买一个新的硬件设备,但是连接上电脑并不能正确执行,于是你决定拨打技术支持电话。
首先你会听到自动回复器的机器合成语音,它提供了针对各种问题的九个常用解决方案,你按照提示操作,机器人将你转接到一位人工客服人员。
客服发现问题的技术性比较强,无法提供任何具体的解决方案。于是他将你转接到一位技术工程师。
最后,工程师告诉了你新硬件设备驱动程序的下载网址,以及操作步骤,你按照说明解决了问题,几经周折,终于大功告成。

概念

- 处理者 Handler 声明了所有具体处理者的通用接口。该接口通常包含用于请求处理的方法,以及设置下一个处理者的方法。
- 基础处理者(Base Handler)是一个可选的类,你可以将所有处理者共用的样本代码放置在其中。通常情况下,该类中定义了一个保存对于下个处理者引用的成员变量。客户端可通过将处理者传递给下个处理者的构造函数或设定方法来创建链。该类还可以实现默认的处理行为:确定下个处理者存在后再将请求传递给它。
- 具体处理者(Concrete Handlers)包含处理请求的实际代码。每个处理者接收到请求后,都必须决定是否进行处理,以及是否沿着链传递请求。处理者通常是独立且不可变的,需要通过构造函数一次性地获得所有必要地数据。
- 客户端(Client)可根据程序逻辑一次性或者动态地生成链。值得注意的是,请求可发送给链上的任意一个处理者,而非必须是第一个处理者。
活学活用
以请假流程为例,一般公司普通员工的请假流程简化如下

普通员工发起一个请假申请,当请假天数小于3天时主管即可审批;当请假天数大于3天时,需要提交给项目经理审批,但若请假天数大于7天,就要提交给总经理审批。
public interface Handler {
/**
* 处理请假
*
* @param days 请假天数
* @return 是否批准
*/
boolean handleHoliday(int days);
/**
* 设置责任链的下一个处理者
*
* @param h 下一个处理者
*/
void setNext(Handler h);
}
public class BaseHandler implements Handler {
private Handler next;
@Override
public boolean handleHoliday(int days) {
if (next != null) {
next.handleHoliday(days);
return true;
} else {
System.out.println("未批准");
return false;
}
}
@Override
public void setNext(Handler h) {
next = h;
}
}
public class LeaderManager extends BaseHandler {
@Override
public boolean handleHoliday(int days) {
if (days <= 3) {
System.out.println("LeaderManager 批准");
return true;
} else {
return super.handleHoliday(days);
}
}
}
public class ProjectManager extends BaseHandler {
@Override
public boolean handleHoliday(int days) {
if (days <= 7) {
System.out.println("ProjectManager 批准");
return true;
} else {
return super.handleHoliday(days);
}
}
}
public class DeptManager extends BaseHandler {
@Override
public boolean handleHoliday(int days) {
System.out.println("DeptManager 批准");
return true;
}
}
public class Client {
public static void main(String[] args) {
Handler leaderManager = new LeaderManager();
Handler projectManager = new ProjectManager();
Handler deptManager = new DeptManager();
leaderManager.setNext(projectManager);
projectManager.setNext(deptManager);
leaderManager.handleHoliday(5);
}
}
真实例子
Android 事件传递机制
- 伪代码
public boolean dispatchTouchEvent(MotionEvent event){
boolean consume = false;
if (onInterceptTouchEvent(event)) {
consume = onTouchEvent(event);
} else {
consume = child.dispatchTouchEvent(event);
}
return consume;
}

使用场景
- 当必须按顺序执行多个处理者时,可以使用该模式。
- 无论你以何种顺序将处理者连接成一条链,所有请求都会严格按照顺序通过链上的处理者。
- 如果所需处理者及其顺序需要在运行时进行改变,可以使用职责链模式。
- 调用者可以根据运行时环境,动态地插入和移除处理者,或者改变其顺序。
纯的与不纯的责任链模式
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。
优缺点
- 优点
- 可控的请求处理的顺序。
- 单一职责原则:每个处理者职责单一,并且对发起操作和执行操作的类进行了解耦。
- 开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。
- 缺点
- 有可能出现请求不被任何处理者处理的情况;
- 责任链建立不当,有可能出现死循环;
和其他设计模式比较
- 常见组合
- 责任链通常和组合模式结合使用。在这种情况下,父组件接收到请求后,可以将请求沿包含子组件的链一直传递至对象树的叶结点。 Android 中 View 及其时间传递机制正是如此;
- 最易混淆
- 责任链和装饰模式的类结构非常相似。两者都依赖递归组合将需要执行的操作传递给一系列对象。但是,两者有几点重要的不同之处。
- 职责链的管理者可以相互独立地执行一切操作,还可以随时停止传递请求。
- 可以在遵循基本接口的情况下扩展对象的行为。
- 装饰无法中断请求的传递。
- 责任链和装饰模式的类结构非常相似。两者都依赖递归组合将需要执行的操作传递给一系列对象。但是,两者有几点重要的不同之处。
最后
最后感谢大家能看到这,希望能带给大家帮助!
同时也希望各位可以帮忙点个赞,关注一下,谢谢大家的支持!
漫漫开发之路,我们只是其中的一小部分……只有不断的学习、进阶,才是我们的出路!才跟得上时代的进步!
我从事Android开发快十年了,今年年初我花近两个月的时间收录整理了一套Android进阶知识体系,如果有想法深入的系统化的去学习,可以Android进阶技术交流(895077617 )免费获取整理版的资料
**,我会把我收录整理的资料都送给大家,帮助大家更快的进阶。
重要的事说三遍,关注+喜欢,让更多需要的朋友们都可以看到并且领到!

