责任链设计模式(过滤器)

责任链设计模式(过滤器、拦截器)


责任链设计模式(Chain of Responsibility)的应用有:Java Web中的过滤器链、Struts2中的拦截器栈。java

先看一个问题:设计模式

给定一个字符串“被就业了:),敏感信息,<script>”,对其中的HTML标记和敏感词进行过滤或替换。
本文主要以该问题设计方法的演变来说解责任链设计模式。ide

第一种设计:没有任何设计模式post

设计了一个MsgProcessor类,完成字符串处理的主要工做。MainClass类是本设计中的测试类。测试

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainClass {
     public static void main(String[] args) {
         //须要被过滤的语句
         String msg = "被就业了:),敏感信息,<script>" ;
 
         //实例化处理类
         MsgProcessor mp = new MsgProcessor(msg);
         String r = mp.process();
 
         System.out.println(r);
     }
 
}
 
public class MsgProcessor {
     private String msg;
     public MsgProcessor(String msg){
         this .msg = msg;
     }
 
     public String process(){
         String r = msg;
         //过滤msg中的HTML标记
         r = r.replace( "<" , "&lt;" ).replace( ">" , "&gt;" );
         //过滤敏感词
         r = r.replace( "敏感" , "" ).replace( "被就业" , "就业" );
 
         return r;
     }
}

第二种设计:增长一个Filter接口this

在第一种设计中,对字符串的全部处理都放在MsgProcessor类中,扩展性极差。若是要过滤字符串中的笑脸(将”:)”替换成”^_^”),则须要改动MSgProcessor中的process方法。spa

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public interface Filter {
     String doFilter(String str);
}
 
public class HtmlFilter implements Filter {
     public String doFilter(String msg) {
         String r = msg;
         //过滤msg中的HTML标记
         r = r.replace( "<" , "&lt;" ).replace( ">" , "&gt;" );
 
         return r;
     }
}
 
public class SensitiveFilter implements Filter {
     public String doFilter(String msg) {
         String r = msg;
         //过滤敏感词
         r = r.replace( "敏感" , "" ).replace( "被就业" , "就业" );
 
         return r;
     }
}
 
public class MsgProcessor {
     private String msg;
     private Filter[] filters = { new HtmlFilter(), new SensitiveFilter()};
 
     public MsgProcessor(String msg){
         this .msg = msg;
     }
 
     public String process(){
         String r = msg;
         for (Filter f : filters){
             r = f.doFilter(r);
         }
         return r;
     }
}

此时,若是须要过滤字符串中的笑脸,只须要建立一个类FaceFilter实现Filter接口,并在MsgProcessor类中的filters字段中登记便可。设计

第三种设计:责任链模式(FilterChain)code

定义:将一个事件处理流程分派到一组执行对象上去,这一组执行对象造成一个链式结构,事件处理请求在这一组执行对象上进行传递。责任链模式的主要参与角色:orm

① 事件处理请求对象(Request)

② 执行对象(Handler)

责任链设计模式(过滤器、拦截器)1838

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class FilterChain implements Filter {
 
     public List<Filter> filters= new ArrayList<Filter>();
 
     public FilterChain addFilter(Filter f){
         filters.add(f);
         return this ;
     }
 
     public String doFilter(String msg) { //执行filters中的doFilter方法便可
         String r = msg;
         for (Filter f : filters){
             r = f.doFilter(r);
         }
         return r;
     }
}
 
public class MsgProcessor {
     private String msg;
     private FilterChain chain = new FilterChain();
 
     public MsgProcessor(String msg,Filter Chain){
         this .msg = msg;
         this .chain = chain;
     }
 
     public String process(){
         return chain.doFilter(msg);
     }
}
 
public class MainClass {
     public static void main(String[] args) {
         //须要被过滤的语句
         String msg = "被就业了:),敏感信息,<script>" ;
 
         //搞一个过过滤链
         FilterChain chain = new FilterChain();
         chain.addFilter( new HtmlFilter()).addFilter( new SensitiveFilter());
         //实例化处理类
         MsgProcessor mp = new MsgProcessor(msg,chain);
         String r = mp.process();
 
         System.out.println(r);
     }
}

责任链模式增强版
上面的实现的过滤链能够用下图a)表示出来,整个过程只对msg过滤了一次。而JavaWeb中的过滤器链和Struts2中的拦截器栈执行的过程能够形象的表示为图b,☆很重要)。

责任链设计模式(过滤器、拦截器)2890

下面用程序模拟JavaWeb中的过滤器,实现相似于对Request和Response的过滤。主要涉及的类以下所示:

责任链设计模式(过滤器、拦截器)2950

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public interface Filter {
     void doFilter(Request req,Response resp,FilterChain chain);
}
 
public class HtmlFilter implements Filter {
     public void doFilter(Request req, Response resp, FilterChain chain) {
         //过滤req.reqStr中的HTML标记
         req.reqStr = req.reqStr.replace( "<" , "&lt;" ).replace( ">" , "&gt;" );
         req.reqStr += "---HtmlFilter()---" ;
         chain.doFilter(req, resp);
         resp.respStr += "---HtmlFilter()---" ;
     }
}
 
public class SensitiveFilter implements Filter {
     public void doFilter(Request req, Response resp, FilterChain chain) {
         // 过滤req.reqStr中的敏感词
         req.reqStr = req.reqStr.replace( "敏感" , "" ).replace( "被就业" , "就业" );
         req.reqStr += "===SensitiveFilter" ;
         chain.doFilter(req, resp);
         resp.respStr += "===SensitiveFilter" ;
     }
}
 
public class FilterChain{
     private List<Filter> filters = new ArrayList<Filter>();
     //调用链上的过滤器时,记录过滤器的位置用
     private int index = 0 ;
 
     public FilterChain addFilter(Filter f){
         filters.add(f);
         return this ;
     }
 
     public void doFilter(Request req, Response resp) {
         if (index == filters.size()) return ;
         //获得当前过滤器
         Filter f = filters.get(index);
         index++;
 
         f.doFilter(req, resp, this );
     }
}
 
public class Request {
     //在Request中只保持了一个reqStr字段记录对Request的操做
     //为了方便模拟,没有将reqStr设置为private
     String reqStr;
}
 
public class Response {
     //在Response中只保持了一个respStr字段记录对Response的操做
     //为了方便模拟,没有将respStr设置为private
     String respStr;
}
package org.flyne.fiter;
 
public class MainClass {
     public static void main(String[] args) {
         // 须要被过滤的语句
         String msg = "被就业了:),敏感信息,<script>" ;
 
         //建立Request、Response对象
         Request req = new Request();
         Response resp = new Response();
         req.reqStr = msg;
         resp.respStr = "response" ;
 
         //搞一个过滤链,链上有两个过滤器
         FilterChain chain = new FilterChain();
         chain.addFilter( new HtmlFilter())
             .addFilter( new SensitiveFilter());
 
         //开始过滤
         chain.doFilter(req, resp);
 
         System.out.println(req.reqStr);
         System.out.println(resp.respStr);
     }
}