责任链(ChainOfResponsibility)
对于设计模式的学习,一定要动手,而且要多次练习,然后慢慢消化和理解,才能明白其精髓。但是,设计模式只是在特殊情景下的特殊解决方案,不要滥用,不要为了使用设计模式而硬生生得去使用。设计模式的使用应该自然、优雅!
问题
2 | public static void main(String[] args) { |
3 | String str = "你好:),这句话中有敏感词汇,需要处理。<script>,敏感!" ; |
4 | MsgProcessor pro = new MsgProcessor(); |
6 | str = pro.processor();--- |
7 | System.out.println(str); |
另一个类:
01 | public class MsgProcessor { |
03 | public String getMsg() { |
06 | public void setMsg(String msg) { |
10 | public String processor(){ |
12 | if ( null != msg && !( "" ).equals(msg.trim())){ |
13 | content = msg.replace( "<" , "{" ) |
16 | content = content.replace( "敏感" , "" ); |
17 | content = content.replace( ":)" , "^V^" ); |
上面的代码完成了对一个字符串的简单过滤,但是很明显这样的代码很不好。扩展性不好,写得也不够好。这样以后需要添加别的过滤功能不是很方便,总是要修改这个类,一点都不灵活,想把对字符串的过滤行为抽象出来,因为这部分是变化的,自然而然想到使用接口。

代码修改为:
1 | public String processor(){ |
2 | if ( null != msg && !( "" ).equals(msg.trim())){ |
3 | msg = new HTMLFilter().doFilter(msg); |
4 | msg = new SmileFilter().doFilter(msg); |
5 | msg = new SensitivityFilter().doFilter(msg); |
这样还是不够灵活,直接在 MsgProcessor 类中添加一个数组来保存过滤器,然后在 processor** 方法中进行多次调用:
修改为:
1 | public String processor(){ |
2 | if ( null != msg && !( "" ).equals(msg.trim())){ |
3 | for (Filter f : filters){ |
这样调整后,所有的过滤器都起作用了,添加起来更加灵活一些,并且过滤器的执行顺序也是可控的。
当多个过滤器组合在一起,就形成了过滤器链,到这里,责任链有点雏形了。
新的问题
如果本来已经存在一个过滤器链条了,我想把一些新的过滤器链加进去,并且加入的顺序可以随意控制(随意组合任意的过滤器链条),该怎么办呢?
定义一个过滤器链类,这这个类中定义添加过滤器的方法,以及运行整个链条上的所有过滤器的方法,并且返回结果。
代码修改为:
MsgProcessor.java :
01 | public class MsgProcessor { |
04 | private FilterChain fc; |
06 | public FilterChain getFc() { |
09 | public void setFc(FilterChain fc) { |
12 | public String getMsg() { |
15 | public void setMsg(String msg) { |
19 | public String processor(){ |
20 | return fc.doFilter(msg); |
FilterChain.java:
01 | public class FilterChain { |
02 | List<Filter> filters = new ArrayList<Filter>(); |
04 | public FilterChain addFilter(Filter filter){ |
09 | public String doFilter(String str){ |
10 | if ( null != str && !( "" ).equals(str.trim())){ |
11 | for (Filter f : filters){ |
12 | str = f.doFilter(str); |
TestMain.java
01 | public class TestMain { |
02 | public static void main(String[] args) { |
03 | String str = "你好:),这句话中有敏感词汇,需要处理。<script>,敏感!" ; |
04 | MsgProcessor mp = new MsgProcessor(); |
06 | FilterChain fc = new FilterChain(); |
07 | fc.addFilter( new HTMLFilter()) |
08 | .addFilter( new SmileFilter()) |
09 | .addFilter( new SensitivityFilter()); |
12 | System.out.println(str); |
写到这里,还是没有解决我们的问题,怎样灵活合并过滤器链呢? 很简单,我们可以将过滤器链这个类,当作一个很大的过滤器来处理,这样就可以了。让 FilterChain 也实现Filter接口,这样就解决了这个问题!完成这一步,就已经有了责任链模式的味道了!
思考实际开发中的问题
在实际开发中,我们见过的过滤器都能进行双向的处理,也就是说,能处理request和response,而且是先挨着处理request,然后再反向处理response,这又是怎么实现的呢?

定义一个Request和Response,在实际的web容器中,容器会帮助我们生成这两个对象,而且在其中封装了很多的东西,在这里,只是模拟,只需简单定义就可以了。
Request.java
2 | private String requestStr; |
3 | public String getRequestStr() { |
6 | public void setRequestStr(String requestStr) { |
7 | this .requestStr = requestStr; |
Response.java
2 | private String responseStr; |
3 | public String getResponseStr() { |
6 | public void setResponseStr(String responseStr) { |
7 | this .responseStr = responseStr; |
定义好这两个类之后,修改之前的程序:
Filter.java
1 | public interface Filter { |
2 | public abstract void doFilter(Request request, Response response); |
别的代码跟着这个接口一起改就可以了,但是你会发现,还是不能实现我们想要的效果,这个时候需要一些编程的手法,我们继续修改Filter接口:
Filter.java
1 | public interface Filter { |
2 | public abstract void doFilter(Request request, Response response, FilterChain filterChain); |
为什么要这样修改,因为只有这样才能把链条握在每一个过滤器手中,有了链条,就可以控制链条了:
FilterChain.java
01 | public class FilterChain implements Filter { |
02 | private List<Filter> filters = new ArrayList<Filter>(); |
04 | public FilterChain addFilter(Filter filter){ |
05 | this .filters.add(filter); |
09 | public void doFilter(Request request, Response response, |
10 | FilterChain filterChain) { |
11 | if (index >= filters.size()) return ; |
12 | Filter f = filters.get(index); |
14 | f.doFilter(request, response, filterChain); |
HTMLFilter.java
01 | public class HTMLFilter implements Filter { |
03 | public void doFilter(Request request, Response response, |
04 | FilterChain filterChain) { |
05 | String str = request.getRequestStr(); |
06 | System.out.println(str); |
07 | filterChain.doFilter(request, response, filterChain); |
08 | String resStr = response.getResponseStr(); |
09 | System.out.println(resStr); |
现在来看,每个过滤器都持有过滤器链,在处理完request后,调用下一个过滤器,由于方法是栈结构,这样就会形成一个过滤器栈,拥有栈的数据结构特点。这也是为什么Struts在配置多个拦截器的时候,成为拦截器栈的原因。
由于栈的数据特点,就能达到我们想要的特点,按照过滤器的次序,依次处理完request,然后再反向依次处理response。这就是责任链模式在实际开发中的使用。