设计模式之5 责任链

时间:2022-10-01 07:59:40

责任链就是通过一连串的过滤器(filter)来对信息进行处理:

1.最简单的实现方案,通过filter数组来实现。

 

filter接口,用来统一方法名。

package com.bjsxt.dp.filter;

//定义一个接口,用来指定方法的名字为doFilter

publicinterface Filter {

    String doFilter(String str);

}

 

FacFilter实现Filter接口

package com.bjsxt.dp.filter;

 

publicclass FaceFilterimplements Filter {

 

    //@Override

    //把:)替换成为^V^

    public String doFilter(String str) {

       return str.replace(":)","^V^");

    }

 

}

 

HTMLFilter实现Filter接口

package com.bjsxt.dp.filter;

 

publicclass HTMLFilterimplements Filter {

 

    //@Override

    //<替换成为[,>替换成]

    public String doFilter(String str) {

       //process the html tag<>

       String r = str.replace('<','[')

                 .replace('>',']');

       return r;

    }

 

}

 

SesitiveFilter实现Filter接口

package com.bjsxt.dp.filter;

 

publicclass SesitiveFilterimplements Filter {

 

    //@Override

    //被就业"替换成为"就业"

    //敏感"替换为“”

    public String doFilter(String str) {

       //process the sensitive words

       String r = str.replace("被就业","就业")

            .replace("敏感","");

      

       return r;

    }

 

}

 

如果不使用责任链,可以在使用者,当中使用一个filter的数组来保存每个filter,并且分别调用每个filterdoFilter方法。

 

专门的字符串处理类:

package com.bjsxt.dp.filter;

 

publicclass MsgProcessor1 {

    private Stringmsg;

    //filter数组

    Filter[] filters = {new HTMLFilter(),new SesitiveFilter(),new FaceFilter()};

 

 

    public String getMsg() {

       returnmsg;

    }

 

    publicvoid setMsg(String msg) {

       this.msg = msg;

    }

   

    public String process() {

      

       String r = msg;

       //对字符串r,调用所有的filter

       for (Filter f:filters) {

           r = f.doFilter(r);

       }

       return r;

      

      

    }

}

 

使用者就只需要给定字符串:

package com.bjsxt.dp.filter;

 

publicclass Main1 {

 

    /**

     *@paramargs

     */

    publicstaticvoid main(String[] args) {

       //对应一条信息当中各种信息进行替换

       Stringmsg ="大家好:)<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";

       MsgProcessor mp = new MsgProcessor();

       mp.setMsg(msg);

      

       Stringresult = mp.process();

       System.out.println(result);

    }

 

}

 

为了实现能灵活的在当前链当中打开一个缺口,加入新的过滤器(链),就提供了责任链这样一种方式。

 

2.通过责任链模式

责任链的主要任务是能够灵活的设定(添加和删除)过滤器的顺序和组合。

   可以有多个责任链。

   责任链本身也是一个过滤器,一个大过滤器,里面包含了很多小过滤器。

 

 

Main是使用者。也就是用户,不需要知道细节的实现。

package com.bjsxt.dp.filter;

 

publicclass Main {

 

    /**

     *@paramargs

     */

    publicstaticvoid main(String[] args) {

       //对应一条信息当中各种信息进行替换

       String msg = "大家好:)<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";

       MsgProcessor mp = new MsgProcessor();

       mp.setMsg(msg);

      

      

       FilterChain fc = new FilterChain();

//链条式编程,可以反复添加多个filter

       fc.addFilter(new HTMLFilter())

         .addFilter(new SesitiveFilter())

         ;

      

       //facefilter添加到fc2当中,那么就有两个fcfc1fc2

       FilterChain fc2 = new FilterChain();

       fc2.addFilter(new FaceFilter());

      

       //因为fc2也实现了filter接口,那么fc2本身也就是一个filter,所以可以被添加到fc当中。

       //所以fc2可以灵活的添加到fc当中的任何位置,由使用者,也就是main来控制。

       fc.addFilter(fc2);

       mp.setFc(fc);

       String result = mp.process();

       System.out.println(result);

    }

 

}

 

MsgProcessor是用来处理消息的,提供了一个porcess()方法。在MsgProcessor当中有一个FilterChain对象。其实这个类可有可没有。也可以把这个类整合到main里面去。

 

package com.bjsxt.dp.filter;

 

publicclass MsgProcessor {

    private Stringmsg;

   

    //filterchain作为一个成员变量放到这边,过滤规则都是有FC来实现。

    FilterChain fc;

   

    public FilterChain getFc() {

       returnfc;

    }

 

    publicvoid setFc(FilterChain fc) {

       this.fc = fc;

    }

 

    public String getMsg() {

       returnmsg;

    }

 

    publicvoid setMsg(String msg) {

       this.msg = msg;

    }

   

    //其实调用的是filterChaindoFilter方法,还是把每个Filter拿出来,每个执行一遍doFilter方法。

    //现在其实process自己什么都不做,都是FC来处理。

    public String process() {

      

      

       returnfc.doFilter(msg);

      

      

    }

}

 

FilterChain当中可以添加和删除filter。本例中只实现了添加,没实现删除。要注意的是,这些filter需要根据使用者的需求(选择哪些filterfilter的顺序),在main里面由使用者来添加的。FilterChain应该是一个很灵活的类。最关键的一步,是它自己也实现了filter接口。从来能够被添加到另一个FilterChain对象当中去,成为别人的一部分。

 

 

package com.bjsxt.dp.filter;

 

import java.util.ArrayList;

import java.util.List;

 

//filterChain自己也实现了filter接口,也就是说,

//filterChain自己也可以作为一个filter对象,被添加到另外一个Filterchain当中去.

//这样就实现了灵活的添加。哪怕是把一根filterChain作为一个大的fitler添加

//到另外一个fitlerChian当中。

publicclass FilterChainimplements Filter {

    //filterChain当中加入一个arraylist来存放filter

    List<Filter> filters = new ArrayList<Filter>();

   

    //fitler加入到arraylist当中

    //注意这里有个技巧,就是把这个方法的返回值设定为这个类自身。那么返回的还是这个类,又可以调用add方法。

    //那么在使用这个类的时候,就可以用 fc.addFilter(new HTMLFilter()).addFilter(newSesitiveFilter());

    //这样的方法来在使用者添加对象。这种方法叫链条式编程。

    public FilterChain addFilter(Filter f) {

       this.filters.add(f);

       returnthis;

    }

    //把原MsgProcessor的处理字符串的方法,放到这里来了,那么FC就是专门用来处理字符串。

    //MsgProcessor和业务逻辑分开。

    public String doFilter(String str) {

       String r = str;

       for(Filter f:filters) {

           r = f.doFilter(r);

       }

       return r;

    }

}

 

 

3.双向责任链模式(主要是顺序的控制,个人感觉是递归思想的应用,当然这里不完全是递归。)

要求:过滤的信息,从客户端上到服务器端需要通过1,2,3这样的过滤,而从服务器到客户端的过滤顺序是3,2,1.双向过滤。而我们已经实现了,从客户端上到服务器端的单项过滤。其实质是一个堆栈结构,是先进后出的顺序。

问题实现的关键是在服务器向客户端返回的时候,需要是3,2,1的顺序。

如果要在服务器到客户端的过滤顺序也实现1,2,3非常的简单,只需要在从客户端上到服务器端调用责任链的时候,也调用对response的处理就可以。那么现在需要反向调用,实现的逻辑就比较复杂。

 

首先是filter接口,注意现在的方法定义当中的参数。

package com.bjsxt.dp.filter;

 

//现在的参数,就是requestresponse,还有chain

//传递的时候,可以是request+空的response

//或者是response+空的request

//注意现在的返回值,不再是string类型,而是把处理完成的信息保存在requestresponse对象当中。

//所以返回值为void

publicinterface Filter {

   

    //FilterChain在这里的意义: filterFC里面,如果给定chain

    //当调用doFilter的时候,就可以指定下一步的FC怎么走

    //灵活,可以实现反向。

    void doFilter(Request request, Response response, FilterChainchain);

}

 

HTMLFilter类,注意在doFilter当中调用了chain.doFilter(request,response, chain);

 

package com.bjsxt.dp.filter;

 

publicclass HTMLFilterimplements Filter {

 

   

 

    //@Override

    publicvoid doFilter(Request request, Response response, FilterChainchain) {

       //process the html tag<>

//     首先处理的request

       request.requestStr = request.requestStr.replace('<','[')

                 .replace('>',']') + "---HTMLFilter()";

//     request处理完成,之后马上调用下一个filter

       chain.doFilter(request, response, chain);

       response.responseStr +="---HTMLFilter()";

    }

 

}

 

SesitiveFilter类,注意在doFilter当中调用了chain.doFilter(request,response, chain);

 

 

package com.bjsxt.dp.filter;

 

publicclass SesitiveFilterimplements Filter {

 

   

 

    //@Override

   

    publicvoid doFilter(Request request, Response response, FilterChainchain) {

       //首先处理的request

       request.requestStr = request.requestStr.replace("被就业","就业")

        .replace("敏感","") + "---SesitiveFilter()";

       //request处理完成,之后马上调用下一个filter

       chain.doFilter(request, response, chain);

      

       response.responseStr +="---SesitiveFilter()";

   

    }

   

   

 

}

 

FilterChain类,大递归,反复调用doFilter方法。

 

package com.bjsxt.dp.filter;

 

import java.util.ArrayList;

import java.util.List;

 

publicclass FilterChainimplements Filter {

    List<Filter> filters = new ArrayList<Filter>();

    //记录index

    intindex = 0;

   

    public FilterChain addFilter(Filter f) {

       this.filters.add(f);

       returnthis;

    }

   

    //@Override

    publicvoid doFilter(Request request, Response response, FilterChainchain) {

       //如果index已经走到了数组的最后。

       if(index ==filters.size())return ;

       //通过index来控制下一个filter是谁。

       Filter f = filters.get(index);

       //指向下一个filter

       index ++;

      

       f.doFilter(request, response, chain);

    }

}

 

 

 

Request

package com.bjsxt.dp.filter;

//模拟,从客户端到服务器的信息,request

publicclass Request {

    String requestStr;

 

    public String getRequestStr() {

       returnrequestStr;

    }

 

    publicvoid setRequestStr(String requestStr) {

       this.requestStr = requestStr;

    }

}

 

Response

package com.bjsxt.dp.filter;

 

//模拟,从服务器到客户端的信息,response

publicclass Response {

    String responseStr;

 

    public String getResponseStr() {

       returnresponseStr;

    }

 

    publicvoid setResponseStr(String responseStr) {

       this.responseStr = responseStr;

    }

   

}

 

 

main类,使用者类:

package com.bjsxt.dp.filter;

//其核心过程,非常像一个大的递归程序。一路调用自己下去,然后一路反向返回。

publicclass Main {

 

    /**

     *@paramargs

     */

    publicstaticvoid main(String[] args) {

       String msg = "大家好:)<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";

       Request request = new Request();

       request.setRequestStr(msg);

      

       Response response = new Response();

       response.setResponseStr("response");

      

       FilterChain fc = new FilterChain();

       fc.addFilter(new HTMLFilter())

         .addFilter(new SesitiveFilter())

         ;    

       //main里面首先,把requestresponse对象传进去,同时把自己也传进去。

       fc.doFilter(request, response, fc);

       System.out.println(request.getRequestStr());

       System.out.println(response.getResponseStr());

    }

 

}

 

 

核心逻辑:

      

   注意方法调用运行的顺序:

      main方法当中开始运行,调用fcdoFilter。这个时候index0fcsize2.

     fcfilter当中,Filter f = filters.get(index);这个时候拿到的是第一个filter。通过index++,这个时候index变成1了。

      马上通过fcdoFilter当中的f.doFilter调用第一个filter。这个时候,index0的这个fc.doFilter就暂停。程序就跳转到HTMLfilterdoFilter当中。

      这里的f就是Filter f = filters.get(index);当中得到那个index=0filter,也就是HTMLfilter,对request处理。request处理完成,马上在HTMLfilterdoFilter方法调用了chain.doFilter.这个时候,HTMLfilterdoFilter方法暂停了。程序就跳转到fcdoFilter当中。

      那么重新来到了fcdoFilter方法当中,要注意现在的index1了。在fcdoFilter当中,Filter f =filters.get(index); 这个时候拿到的是第二个filter。拿到了第二个filter之后,通过index++,这个时候index变成2了。马上通过f.doFilter调用第二个filter。这个时候,index1的这个fc.doFilter就也暂停。程序就跳转到SensitivefilterdoFilter当中。

      这里的fFilter f = filters.get(index);当中得到那个index=1filter,也就是第二个filter,是Sensitivefilter,对request处理。 request处理完成,马上在SensitivefilterdoFilter方法调用了chain.doFilter.这个时候,SensitivefilterdoFilter方法暂停了。程序就跳转到fcdoFilter当中。

      那么再一次重新来到了fcdoFilter方法当中,现在的index2了。因为if(index == filters.size()) return ;现在index2,所以就返回了。那么request处理完毕。

 

      返回的位置返回到上一个没有执行完毕的方法,也就是最后一个调用chain.doFilter方法的位置。那么来到SensitivefilterdoFilter方法当中。Sensitivefilter就继续执行,把处理response的业务逻辑完成。

      SensitivefilterdoFilter方法处理结束,就要返回到上一个没有执行完毕的方法。也就是回到调用它的方法,也就是当index等于1的时候,fc.doFilter方法当中。

      index等于1fc.doFilter顺利执行结束,那么回到调用chain.doFilter的地方,也就是HTMLfilterdoFilter方法。

      同样HTMLfilterdoFilter方法继续执行,把处理response的业务逻辑完成,返回到调用它的位置。也就是当index等于0的时候,fc.doFilter方法当中。

      fc.doFilter顺利执行结束, main方法结束。