设计模式之责任链模式(Chain of Responsibility)
简单概念
当一个请求需要经过多级过滤处理时,这个多级处理的每一个流程串起来就是一个责任链,每一个流程负责自己的责任。这个请求可能经过了多个流程的处理,也可能只经过了一个流程的处理,甚至没有流程处理。
例子:
某媒体需要对用户发布的文章做一些处理,需要去除敏感词,去除HTML代码,补全链接等。(就像打游戏,在队友特别坑的情况下,我们都用拼音来骂队友:‘laji’,防止系统处理成‘**’)
还有典型的javaEE java.javax.servlet Filter过滤器,这个最后再说。
上代码:
介绍一下待出场的类,Msg,文章类,发布待处理的文章;
package com.zl.chainOfResponsibility;
public class Msg {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Msg{" +
"msg='" + msg + '\'' +
'}';
}
}
Filter,文章处理抽象接口;
package com.zl.chainOfResponsibility;
public interface Filter {
public void doFilter(Msg msg);
}
SensitiveWordFilter,Filter实现类,敏感词的过滤处理(具体情况具体处理,为了简便,我就只处理了“草”字)
package com.zl.chainOfResponsibility;
public class SensitiveWordFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replaceAll("草", "*");
msg.setMsg(s);
}
}
HTMLFilter,Filter实现类,html代码过滤处理,例如文章有“<p>xxx</p>”字段,为保护文章样式,需要替换掉<p></p>(这里也是简便处理)
package com.zl.chainOfResponsibility;
public class HTMLFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s =msg.getMsg();
s = s.replace("<p>","");
s = s.replace("</p>","");
msg.setMsg(s);
}
}
LinkFilter,Filter实现类,链接补全过滤处理
package com.zl.chainOfResponsibility;
public class LinkFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replace("xxxxxx.com", "http://www.xxxxxx.com");
msg.setMsg(s);
}
}
接着main方法测试
package com.zl.chainOfResponsibility;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
new HTMLFilter().doFilter(msg);
new SensitiveWordFilter().doFilter(msg);
new LinkFilter().doFilter(msg);
System.out.println(msg);
}
}
![](https://img2020.cnblogs.com/blog/1153934/202009/1153934-20200915110543085-1442334692.png)
这就是责任链吗?
显然还不够完善,当我们需要添加扩展新的过滤处理时,主体程序main方法中需要添加修改代码,这并不符合对内修改关闭,对外扩展开放的原则。
升级:
抽象出“处理链条”,我先内置了3个默认过滤处理
package com.zl.chainOfResponsibility;
import java.util.LinkedList;
import java.util.List;
public class FilterChain implements Filter{
static List<Filter> filters = new LinkedList<>();
static {
filters.add(new SensitiveWordFilter());
filters.add(new HTMLFilter());
filters.add(new LinkFilter());
}
public void doFilter(Msg msg){
for (int i = 0; i < filters.size(); i++) {
filters.get(i).doFilter(msg);
}
}
public void add(Filter filter){
filters.add(filter);
}
public void remove(Filter filter){
filters.remove(filter);
}
}
此时的主体Main类
package com.zl.chainOfResponsibility;
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
FilterChain chain = new FilterChain();
chain.doFilter(msg);
System.out.println(msg);
}
}
至此大功告成,当我们再需要扩展新的过滤处理,或者需要移除默认配置时,只需要通过配置类,或者配置文件去修改即可。主体类再也不用变了。
为什么FilterChain也实现了Filter接口?
每一个单独的Filter实现是整个FilterChain的一部分,那部分的FliterChain不也是整体FilterChain的一部分嘛,这样的话链条和链条之间也是可以连接的移除的。
怎么样中断链条的执行?
把doFilter方法改成带返回值的,如boolean,如果当前条件满足终止条件返回相应值即可。
最后来谈谈javaEE中 java.javax.servlet Filter
先把Api粘过来
Filter接口:
FilterChain接口:
那么Java官方是怎么设计责任链的呢?
如上图,假如我们定义了三个Filter的实现
当一个客户端请求进来后,它依次经过filter1,filter2,filter3的处理;
并且当服务器响应数据返回时也通过这些filter进行后续的处理,它依次经过filter3,filter2,filter1
我们还通过上面的例子进行一下模拟:
将上述Msg类更名Request类(方便理解)
package com.zl.chainOfResponsibility.servlet;
public class Request {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Msg{" +
"msg='" + msg + '\'' +
'}';
}
}
添加Response类
package com.zl.chainOfResponsibility.servlet;
public class Response {
String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Response{" +
"msg='" + msg + '\'' +
'}';
}
}
Filter接口
(让每一个filter的实现者都持有整个链条的引用)
package com.zl.chainOfResponsibility.servlet;
public interface Filter {
public void doFilter(Request req, Response resp, FilterChain chain);
}
SensitiveWordFilter实现
(在每一个filter实现中,当它处理完了request请求,紧接着就通过持有链条的引用去调用下一个filter实现,直到所有的filters都执行完毕)
package com.zl.chainOfResponsibility.servlet;
public class SensitiveWordFilter implements Filter {
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
String s = req.getMsg();
s = s.replaceAll("草", "*");
req.setMsg(s);
chain.doFilter(req, resp, chain);
String s2 = resp.getMsg();
s2 = s2.concat("SensitiveWordFilter__");
resp.setMsg(s2);
}
}
HTMLFilter实现
package com.zl.chainOfResponsibility.servlet;
public class HTMLFilter implements Filter {
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
String s =req.getMsg();
s = s.replace("<p>","");
s = s.replace("</p>","");
req.setMsg(s);
chain.doFilter(req, resp, chain);
String s2 = resp.getMsg();
s2 = s2.concat("HTMLFilter__");
resp.setMsg(s2);
}
}
LinkFilter实现
package com.zl.chainOfResponsibility.servlet;
public class LinkFilter implements Filter {
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
String s = req.getMsg();
s = s.replace("xxxxxx.com", "http://www.xxxxxx.com");
req.setMsg(s);
chain.doFilter(req, resp, chain);
String s2 = resp.getMsg();
s2 = s2.concat("LinkFilter__");
resp.setMsg(s2);
}
}
把Filter串起来的链条类FilterChain
(在FilterChain中判断当所有的filters都执行完毕时,开始回溯,依次再反向调用filters处理服务器的响应数据)
package com.zl.chainOfResponsibility.servlet;
import java.util.LinkedList;
import java.util.List;
public class FilterChain implements Filter {
int index = 0;
static List<Filter> filters = new LinkedList<>();
static {
filters.add(new SensitiveWordFilter());
filters.add(new HTMLFilter());
filters.add(new LinkFilter());
}
public void doFilter(Request req, Response resp, FilterChain chain){
if (filters.size() == index){
return;
}
Filter filter = filters.get(index);
index++;
filter.doFilter(req, resp, chain);
}
public void add(Filter filter){
filters.add(filter);
}
public void remove(Filter filter){
filters.remove(filter);
}
}
最后Main主体类
package com.zl.chainOfResponsibility.servlet;
public class Main {
public static void main(String[] args) {
Request req = new Request();
req.setMsg("<p>你好我是某某某</p>,我的个人网站是xxxxxx.com,草");
Response resp = new Response();
resp.setMsg("");
FilterChain chain = new FilterChain();
chain.doFilter(req, resp, chain);
System.out.println(req);
System.out.println(resp);
}
}
测试结果:(我们在FilterChain中通过静态块默认初始化链条顺序为SensitiveWordFilter,HTMLFilter,LinkFilter)