概念
职责链模式(Chain of Responsibility)
使多个对象都有机会处理同一个请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链设计模式中的角色
Handler
抽象处理者(定义一个处理请求的接口,接口可以定义出一个方法,以设定和返回对下家的引用。通常由一个抽象类或接口实现)
Concrete Handler
具体处理者(具体请求者在接受到请求后,如果满足条件则自己处理请求,否则将请求传到下家。具体处理者持有下家对象的引用)
Client
客户端(调用者)
实战案例
现在我们模拟一个场景:论坛用户发表帖子,但是常常会有用户发一些不良的信息,如广告信息、涉黄信息、涉及政治的敏感词等。这时我们就可以使用责任链模式来过滤用户发表的信息。
先定义所有责任链对象的父类:
package com.wx.wxjob.designPatterns.zerenlian;
/**
* FileName: PostHandler
* Author: pengyd
* Date: 2020/5/19
* function: 帖子处理器
*/
public abstract class PostHandler {
protected PostHandler postHandler;
public void setPostHandler(PostHandler postHandler){
this.postHandler = postHandler;
}
public abstract void hangdlerRequest(Post post);
protected final void next(Post post){
if(this.postHandler != null){
this.postHandler.hangdlerRequest(post);
}
}
}
父类 Handler 主要封装了传递请求等方法,其中要注意的有以下几点:
-
successor ( 后继者 ),这个属性很重要,它保存了责任链中下一个处理器。
-
在 next() 方法中( 方法名自己随便取 ),当请求传递到最后一个责任对象时,已经没有后继者继续处理请求了,因此要对 successor 做判空处理,避免抛出空指针异常。
-
处理请求的 handlerRequest 的入参和返回类型可以根据实际情况修改,可以在该方法中抛出异常来中断请求。
广告处理器:
package com.wx.wxjob.designPatterns.zerenlian;
/**
* FileName: ADHandler
* Author: pengyd
* Date: 2020/5/19
* function: 广告处理器
*/
public class ADHandler extends PostHandler{
@Override
public void hangdlerRequest(Post post) {
// 需要处理的消息
String content = post.getContent();
content = content.replaceAll("广告", "****");
post.setContent(content);
next(post);
}
}
涉黄处理器:
package com.wx.wxjob.designPatterns.zerenlian;
/**
* FileName: YellowHandler
* Author: pengyd
* Date: 2020/5/19
* function: 黄色内容过滤器
*/
public class YellowHandler extends PostHandler {
@Override
public void hangdlerRequest(Post post) {
// 需要处理的消息
String content = post.getContent();
content = content.replaceAll("黄色", "****");
post.setContent(content);
// 传递给下一个处理器
next(post);
}
}
调用:
package com.wx.wxjob.designPatterns.zerenlian;
/**
* FileName: Handler
* Author: pengyd
* Date: 2020/5/19
* function: 调用
*/
public class Handler {
public static void main(String[] args) {
PostHandler adHandler = new ADHandler();
PostHandler yellowHandler = new YellowHandler();
adHandler.setPostHandler(yellowHandler);
Post post = new Post();
post.setContent("我是正常内容 我是广告 我是黄色 ");
adHandler.hangdlerRequest(post);
System.out.println(post);
}
}
总结
责任链模式经常用于过滤器,拦截器,事件( 鼠标键盘事件,冒泡事件等 )等场景。
优点
-
请求者和接收者解耦;
-
可以动态地增加或减少责任链上的对象,或者修改顺序。
缺点
-
调用者不知道请求可能被哪些责任链对象处理,不利于排错;
-
用户请求可能被责任链中途拦截,最终未必被真正执行,这点既是优点也是缺点,我们可以利用它做权限控制拦截器。