什么是责任链模式?
责任链模式是一种对象行为模式。顾名思义,责任链就是把承担不同责任的对象通过某种方式连接在一起形成一条链。当客户端把请求发送到这个责任链上的时候,本质上就是在链上不同的对象之间流转,直到链上的某个对象可以处理该请求,或者每个对象都处理该请求。
根据链上对象对请求的不同处理方式,责任链模式有两类:
(1) 纯责任链模式
- 一个具体的处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家。不允许出现某一个具体处理者对象在承担了一部分或者全部责任后,又将责任向下传递的情况。
- 一个请求必须要被某一个处理者对象所接收,不允许出现没被处理的情况。
(2) 非纯责任链模式
- 允许一个请求被某个处理者对象接收之后,再往下传递的情况
- 不强求一个请求必须被处理
为什么要使用责任链模式?
责任链模式可以把特定行为转换成被称作处理者(Processor)的独立对象。这样就可以有效的把复杂逻辑分成不同的对象,然后把这些对象链接起来,从而降低代码的复杂度。
责任链模式适用于条件连续检查的情况,我们这里举一个非纯责任链模式的例子。
比如你在某电商网站看到一件商品想留言,这个过程可能就涉及到好几个条件检查,比如你是否登录了?为了避免恶意差评可能还会要求你购买了这件商品之后才让你留言,或者检查一下你的留言里是否有敏感词汇等等。
如果不用责任链模式,我们可能会有如下一系列检查条件
public class Client {
public static void main(String[] args) {
if(!login) { // 用户没有登录的话,则不能评论
return;
}
if(!bought) { // 用户没有购买该产品的话,则不能评论
return;
}
if(hasSensitiveWords) { // 用户评论包含敏感词汇,则不能评论
return;
}
leaveComments();
}
}
这样就把所有判断逻辑都聚合在一个类里,如果检查的条件继续增多的话会造成代码的复杂性增大,降低代码的可维护性。
如何使用责任链模式?
在责任链模式中,一个指导思想就是所有的处理者类都要实现同一个接口。并且每个处理者对象都持有责任链中下一个处理者对象的引用。
- 处理者接口(Handler Interface):声明了所有具体处理者类的通用接口。通常包含所有具体处理者类处理请求的方法,但有时也会包含设置后继处理者对象的方法
- 具体处理者类(Concrete Handler): 包含了处理请求的具体代码,每个处理者接收到请求后,都必须决定是否进行处理,以及是否交给下一个处理者对象。
我们将上面的例子用责任链模式来实现以下
public interface CommentHandler {
void setSuccessor(CommentHandler next);
boolean process();
}
public class CheckLoginHandler implements CommentHandler {
private CommentHandler next;
@Override
public void setSuccessor(CommentHandler next) {
this.next = next;
}
@Override
public boolean process() {
if (!login) { // 如果用户没有登录,就返回false
return false;
}
if (next == null) {
return true; // 没有后继处理者对象,说明当前是最后一个处理者了,可以返回true
} else {
return next.process(); // 交给下一个处理者对象处理
}
}
}
public class CheckBoughtHandler implements CommentHandler {
private CommentHandler next;
@Override
public void setSuccessor(CommentHandler next) {
this.next = next;
}
@Override
public boolean process() {
if (!bought) { // 如果用户没有购买过这个商品,就返回false
return false;
}
if (next == null) {
return true; // 没有后继处理者对象,说明当前是最后一个处理者了,可以返回true
} else {
return next.process(); // 交给下一个处理者对象处理
}
}
}
public class CheckSensitiveWordHandler implements CommentHandler {
private CommentHandler next;
@Override
public void setSuccessor(CommentHandler next) {
this.next = next;
}
@Override
public boolean process() {
if (hasSensitiveWord) { // 如果用户评论包含敏感词汇,就返回false
return false;
}
if (next == null) {
return true; // 没有后继处理者对象,说明当前是最后一个处理者了,可以返回true
} else {
return next.process(); // 交给下一个处理者对象处理
}
}
}
public class Client {
public static void main(String[] args) {
CommentHandler checkLoginHandler = new CheckLoginHandler();
CommentHandler checkBoughtHandler = new CheckBoughtHandler();
CommentHandler checkSensitiveWordHandler = new CheckSensitiveWordHandler();
// 设置后继处理者对象
checkLoginHandler.setSuccessor(checkBoughtHandler);
checkBoughtHandler.setSuccessor(checkSensitiveWordHandler);
if (checkLoginHandler.process()) { // 会一路调用三个handler的process方法
leaveComment();
}
}
}
上面这个例子我们就把每个检查条件封装到各个独立的对象里,从而让客户端的代码看起来浅显易懂。并且我们可以动态配置检查条件,以后增加或者删除检查条件所做的工作会少很多。
总结
责任链模式的优点
- 通过把处理逻辑封装成一个个独立的处理者对象,解耦了调用者和处理者。调用者不需要知道处理链的内部逻辑。
- 增强了给对象指派职责的灵活性。通过增删链内成员或者调换它们的次序,可以动态的改变责任链的功能。
但同时我们也应该意识到这种模式的缺点
责任链模式的缺点
- 由于新增了很多类,或者出现比较长的责任链,会对系统的性能造成影响。
- 可能不容易观察运行时的特征,有碍于调试。