概念
责任链模式为某个请求创建一个对象链,每个对象依次检查此请求,并对其进行处理,或者将它传给链中的下一个对象。
链表是很常见一种数据结构,责任链模式的结构其实和链表相差无几,唯一的区别就是责任链模式中所有的对象都有一个共同的父类(或接口):
在责任链模式中,N个 Handler 子类都处理同一个请求,只不过具体的职责有所差别。
当有一个请求进入时,先经过 AHandler 的 handlerRequest 方法,然后再把请求传递给 BHandler,B 处理完再把请求传递给 CHandler,以此类推,形成一个链条。链条上的每一个对象所承担的责任各不相同,这就是责任链模式。
例子
现在我们模拟一个场景:论坛用户发表帖子,但是常常会有用户一些不良的信息,如广告信息,涉黄信息,涉及政治的敏感词等。这时我们就可以使用责任链模式来过滤用户发表的信息。
先定义所有责任链对象的父类:
/**
* 帖子处理器
*/
public abstract class PostHandler {
/**
* 后继者
*/
protected PostHandler successor;
public void setSuccessor(PostHandler handler){
this.successor = handler;
}
public abstract void handlerRequest(Post post);
protected final void next(Post post){
if(this.successor != null){
this.successor.handlerRequest(post);
}
}
}
父类 Handler 主要封装了传递请求等方法,其中要注意的有两点:
- successor,后继者,这个属性很重要,它保存了责任链中下一个处理器
- 在 next() 方法中(方法名自己随便取),当请求传递到最后一个责任对象时,已经没有后继者继续处理请求了,因此要对 successor 做判空处理,避免抛出空指针异常。
- 处理请求的handlerRequest 的入参和返回类型可以根据实际情况修改,可以在该方法中抛出异常来中断请求
广告处理器:
/**
* 广告处理器
*/
public class AdHandler extends PostHandler {
@Override
public void handlerRequest(Post post) {
//屏蔽广告内容
String content = post.getContent();
//.....
content = content.replace("广告","**");
post.setContent(content);
System.out.println("过滤广告...");
//传递给下一个处理器
next(post);
}
}
涉黄处理器:
/**
* 涉黄处理器
*/
public class YellowHandler extends PostHandler {
@Override
public void handlerRequest(Post post) {
//屏蔽涉黄内容
String content = post.getContent();
//.....
content = content.replace("涉黄","**");
post.setContent(content);
System.out.println("过滤涉黄内容...");
//传递给下一个处理器
next(post);
}
}
调用:
//创建责任对象
PostHandler adHandler = new AdHandler();
PostHandler yellowHandler = new YellowHandler();
PostHandler swHandler = new SensitiveWordsHandler();
//形成责任链
yellowHandler.setSuccessor(swHandler);
adHandler.setSuccessor(yellowHandler);
Post post = new Post();
post.setContent("我是正常内容,我是广告,我是涉黄,我是敏感词,我是正常内容");
System.out.println("过滤前的内容为:"+post.getContent());
post = adHandler.handlerRequest(post);
System.out.println("过滤后的内容为:"+post.getContent());
总结
可能大家有疑问,为什么不把所有的过滤器写在一个方法里呢?因为这样做又破坏了开放封闭原则。我们需要使用责任链模式,能够在不修改已有代码的情况下扩展新功能。
责任链模式将常用于过滤器,拦截器,事件(鼠标键盘事件,冒泡事件等)等场景
优点
- 请求者和接收者解耦
可以动态的增加或减少责任链上的对象,或者修改顺序
缺点
- 调用者不知道请求可能被哪些责任链对象处理,不利于排错
用户请求可能被责任链中途拦截,最终未必被真正执行,这点既是优点也是缺点,我们可以利用它做权限控制拦截器