责任链模式详解及其使用示例
保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/70/ )。
在有些场景下,一个目标对象可能需要经过多个对象的处理。例如我们要筹办一个校园晚会,需要针对演员进行如下的准备工作:
- 给演员发送邮件,告知晚会时间地点,该工作由邮件发送员负责。
- 根据演员性别为其准备衣服,该工作由物资管理员负责。
- 如果演员未成年,则为其安排校车接送,该工作由对外联络员负责。
下面代码展示了这一过程,每一个演员都要好三个工作人员打交道。
// 不使用责任链模式
System.out.println("不使用责任链模式:");
// 创建三个工作人员实例
MailSender mailSender = new MailSender();
MaterialManager materialManager = new MaterialManager();
ContactOfficer contactOfficer = new ContactOfficer();
// 依次处理每个参与者
for (Performer performer : performerList) {
System.out.println("process " + performer.getName() + ":");
new MailSender().handle(performer);
new MaterialManager().handle(performer);
new ContactOfficer().handle(performer);
System.out.println("---------");
}
而责任链模式将多个处理器组装成一个链条,被处理对象被放置到链条的起始端后,会自动在整个链条上传递和处理。这样被处理对象不需要和每个处理器打交道,也不需要了解整个链条的传递过程,于是便实现了被处理对象和单个处理器的解耦。
为实现责任链模式,我们首先创建了一个处理器抽象类Handler,如下所示。
public abstract class Handler {
// 当前处理器的下一个处理器
private Handler nextHandler;
/**
* 当前处理器的处理逻辑,交给子类实现
* @param performer 被处理对象
*/
public abstract void handle(Performer performer);
/**
* 触发当前处理器,并在处理结束后将被处理对象传给后续处理器
* @param performer 被处理对象
*/
public void triggerProcess(Performer performer) {
handle(performer);
if (nextHandler != null) {
nextHandler.triggerProcess(performer);
}
}
/**
* 设置当前处理器的下一个处理器
* @param nextHandler 下一个处理器
* @return 下一个处理器
*/
public Handler setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
return nextHandler;
}
}
然后每个处理器需要继承该抽象类Handler,并实现自身的handle方法。下图是责任链模式的类图。
在调用时,我们需要先组装好整个责任链,然后将被处理对象交给责任链处理即可,该过程如下所示。
// 使用责任链模式
System.out.println("使用责任链模式:");
// 创建责任链
Handler handlerChain = new MailSender();
handlerChain.setNextHandler(new MaterialManager()).setNextHandler(new ContactOfficer());
// 依次处理每个参与者
for (Performer performer : performerList) {
System.out.println("process " + performer.getName() + ":");
handlerChain.triggerProcess(performer);
System.out.println("---------");
}
这样,每个演员不需要和工作人员直接打交道,也不需要关心责任链上到底有多少个工作人员。
责任链模式不仅降低了被处理对象和处理器之间的耦合,还使得我们可以更为灵活地组建处理过程。例如我们可以很方便地向责任链中增删除处理器或者调整处理器的顺序。
许多关于责任链模式的介绍中认为责任链中只能有一个处理器生效,我们认为这是狭隘的。在责任链中,可以有一个、多个甚至零个处理器生效。并且,责任链的组建方式也应该是灵活的。本节实例中是使用单链表组件的责任链,实际使用过程中也可以根据需要使用列表、包装等方式来组建和管理责任链。
以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。
这是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,并且附带有示例项目源码,MyBatis的全中文注解。书籍还总结了大量的编程知识和架构经验,对提升编程和架构能力十分有用。
MyBatis中的插件便是使用责任链模式实现的,想了解MyBatis插件原理和创建MyBatis插件的读者,可以参考上述书籍。
可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。
