设计模式之责任链(ChainOfResponsibility)

责任链(ChainOfResponsibility)

对于设计模式的学习,必定要动手,并且要屡次练习,而后慢慢消化和理解,才能明白其精髓。可是,设计模式只是在特殊情景下的特殊解决方案,不要滥用,不要为了使用设计模式而硬生生得去使用。设计模式的使用应该天然、优雅!java

问题

1 public class TestMain {
2 public static void main(String[] args) {
3     String str = "你好:),这句话中有敏感词汇,须要处理。<script>,敏感!";
4     MsgProcessor pro = new MsgProcessor();
5     pro.setMsg(str);
6     str = pro.processor();---
7     System.out.println(str);
8 }
9 }

另外一个类:web

01 public class MsgProcessor {
02 private String msg;
03 public String getMsg() {
04     return msg;
05 }
06 public void setMsg(String msg) {
07     this.msg = msg;
08 }
09
10 public String processor(){
11     String content = "";
12     if(null != msg && !("").equals(msg.trim())){
13         content = msg.replace("<", "{")
14         .replace(">", "}");
15
16         content = content.replace("敏感", "");
17         content = content.replace(":)", "^V^");
18     }
19     return content;
20
21 }

上面的代码完成了对一个字符串的简单过滤,可是很明显这样的代码很很差。扩展性很差,写得也不够好。这样之后须要添加别的过滤功能不是很方便,老是要修改这个类,一点都不灵活,想把对字符串的过滤行为抽象出来,由于这部分是变化的,天然而然想到使用接口。编程

使用接口来剥离行为

代码修改成:设计模式

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);
6     }
7     return msg;
8 }

这样仍是不够灵活,直接在  MsgProcessor  类中添加一个数组来保存过滤器,而后在  processor** 方法中进行屡次调用:数组

修改成:数据结构

1 public String processor(){
2     if(null != msg && !("").equals(msg.trim())){
3         for(Filter f : filters){
4             msg = f.doFilter(msg);
5         }
6     }
7     return msg;
8 }

这样调整后,全部的过滤器都起做用了,添加起来更加灵活一些,而且过滤器的执行顺序也是可控的。ide

当多个过滤器组合在一块儿,就造成了过滤器链,到这里,责任链有点雏形了。学习

新的问题

若是原本已经存在一个过滤器链条了,我想把一些新的过滤器链加进去,而且加入的顺序能够随意控制(随意组合任意的过滤器链条),该怎么办呢?this

定义一个过滤器链类,这这个类中定义添加过滤器的方法,以及运行整个链条上的全部过滤器的方法,而且返回结果。url

代码修改成:

MsgProcessor.java :

01 public class MsgProcessor {
02 private String msg;
03
04 private FilterChain fc;
05
06 public FilterChain getFc() {
07     return fc;
08 }
09 public void setFc(FilterChain fc) {
10     this.fc = fc;
11 }
12 public String getMsg() {
13     return msg;
14 }
15 public void setMsg(String msg) {
16     this.msg = msg;
17 }
18
19 public String processor(){
20     return fc.doFilter(msg);
21 }
22 }

FilterChain.java:

01 public class FilterChain {
02 List<Filter> filters = new ArrayList<Filter>();
03
04 public FilterChain addFilter(Filter filter){
05     filters.add(filter);
06     return this;
07 }
08
09 public String doFilter(String str){
10     if(null != str && !("").equals(str.trim())){
11         for(Filter f : filters){
12             str = f.doFilter(str);
13         }
14     }
15     return str;
16 }
17 }

TestMain.java

01 public class TestMain {
02 public static void main(String[] args) {
03     String str = "你好:),这句话中有敏感词汇,须要处理。<script>,敏感!";
04     MsgProcessor mp = new MsgProcessor();
05     mp.setMsg(str);
06     FilterChain fc = new FilterChain();
07     fc.addFilter(new HTMLFilter())
08     .addFilter(new SmileFilter())
09     .addFilter(new SensitivityFilter());
10     mp.setFc(fc);
11     str = mp.processor();
12     System.out.println(str);
13 }
14 }

写到这里,仍是没有解决咱们的问题,怎样灵活合并过滤器链呢? 很简单,咱们能够将过滤器链这个类,看成一个很大的过滤器来处理,这样就能够了。让 FilterChain 也实现Filter接口,这样就解决了这个问题!完成这一步,就已经有了责任链模式的味道了!

思考实际开发中的问题

在实际开发中,咱们见过的过滤器都能进行双向的处理,也就是说,能处理request和response,并且是先挨着处理request,而后再反向处理response,这又是怎么实现的呢?
过滤器链图

定义一个Request和Response,在实际的web容器中,容器会帮助咱们生成这两个对象,并且在其中封装了不少的东西,在这里,只是模拟,只需简单定义就能够了。

Request.java

1 public class Request {
2 private String requestStr;
3 public String getRequestStr() {
4     return requestStr;
5 }
6 public void setRequestStr(String requestStr) {
7     this.requestStr = requestStr;
8 }
9 }

Response.java

1 public class Response {
2 private String responseStr;
3 public String getResponseStr() {
4     return responseStr;
5 }
6 public void setResponseStr(String responseStr) {
7     this.responseStr = responseStr;
8 }
9 }

定义好这两个类以后,修改以前的程序:

Filter.java

1 public interface Filter {
2     public abstract void doFilter(Request request, Response response);
3 }

别的代码跟着这个接口一块儿改就能够了,可是你会发现,仍是不能实现咱们想要的效果,这个时候须要一些编程的手法,咱们继续修改Filter接口:

Filter.java

1 public interface Filter {
2     public abstract void doFilter(Request request, Response response, FilterChain filterChain);
3 }

为何要这样修改,由于只有这样才能把链条握在每个过滤器手中,有了链条,就能够控制链条了:

FilterChain.java

01 public class FilterChain implements Filter {
02 private List<Filter> filters = new ArrayList<Filter>();
03 private int index = 0;
04 public FilterChain addFilter(Filter filter){
05     this.filters.add(filter);
06     return this;
07 }
08 @Override
09 public void doFilter(Request request, Response response,
10         FilterChain filterChain) {
11     if(index >= filters.size()) return;
12     Filter f = filters.get(index);
13     index++;
14     f.doFilter(request, response, filterChain);
15 }
16 }

HTMLFilter.java

01 public class HTMLFilter implements Filter {
02 @Override
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);
10 }
11 }

如今来看,每一个过滤器都持有过滤器链,在处理完request后,调用下一个过滤器,因为方法是栈结构,这样就会造成一个过滤器栈,拥有栈的数据结构特色。这也是为何Struts在配置多个拦截器的时候,成为拦截器栈的缘由。 因为栈的数据特色,就能达到咱们想要的特色,按照过滤器的次序,依次处理完request,而后再反向依次处理response。这就是责任链模式在实际开发中的使用。

相关文章
相关标签/搜索