责任链设计模式(Chain of Responsibility)的应用有:Java Web中的过滤器链、Struts2中的拦截器栈。
先看一个问题:
给定一个字符串“被就业了:),敏感信息,<script>”,对其中的HTML标记和敏感词进行过滤或替换。
本文主要以该问题设计方法的演变来讲解责任链设计模式。第一种设计:没有任何设计模式
设计了一个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( "<" , "<" ).replace( ">" , ">" ); //过滤敏感词 r = r.replace( "敏感" , "" ).replace( "被就业" , "就业" ); return r; } } |
第二种设计:增加一个Filter接口
在第一种设计中,对字符串的所有处理都放在MsgProcessor类中,扩展性极差。如果要过滤字符串中的笑脸(将”:)”替换成”^_^”),则需要改动MSgProcessor中的process方法。
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( "<" , "<" ).replace( ">" , ">" ); 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)
定义:将一个事件处理流程分派到一组执行对象上去,这一组执行对象形成一个链式结构,事件处理请求在这一组执行对象上进行传递。责任链模式的主要参与角色:
① 事件处理请求对象(Request)
② 执行对象(Handler)
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,☆很重要)。
下面用程序模拟JavaWeb中的过滤器,实现类似于对Request和Response的过滤。主要涉及的类如下所示:
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( "<" , "<" ).replace( ">" , ">" ); 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); } } |