本次的责任链模式依旧是基于马士兵老师的设计模式中责任链模式教学而进行的相关练习。 在责任链模式的(上)中,我们只是对于一个字符串进行了相关的过滤,并且通过了责任链的模式进行了相关封装。然而,对于一般WEB情况,通常来说,我们向服务器发送一个请求(在本示例中我们看成是一个字符串),这个请求经过层层过滤,传送到了服务器以后,服务器在接受了这个请求之后,应当给予这个请求一个回应(同样把回应看作一个字符串),并且再次通过层层过滤输出到客户端面前。 好了,我们首先建立两个类(Request、Response)来模拟请求端与回应端,如下:
public class Request { PRivate String requestStr= null; public String getRequestStr() { return requestStr; } public void setRequestStr(String requestStr) { this.requestStr = requestStr; }}public class Response { private String responseStr = null; public String getResponseStr() { return responseStr; } public void setResponsetrStr(String responseStr) { this.responseStr = responseStr; }}好了,我同样采取类似与在(上)中的思想,针对与所有过滤器Filter我们先创建一个接口Filter,其中有一个方法,其参数能够处理两个对象,也就是上述的请求对象与回应对象,如下所示:
public interface Filter { void doFilter(Request request, Response response);}针对于不同的Filter,我们先后创建三个具体的Filter类实现这个这个接口:
//下面这个类用来替换笑脸,在请求字符串后加上"+++Face",在回应字符串上加上后缀"---Face"public class FaceFilter implements Filter { public void doFilter(Request request, Response response) { request.setRequestStr(request.getRequestStr().replace(":)", "^-^") + "+++Face"); response.setResponseStr(response.getResponseStr() + "---Face"); }}//下面这个类用来把“帅”替换成“*”,在请求字符串后加上"+++Sensitive",在回应字符串上加上后缀"---Sensitive"public class SensitiveFilter implements Filter { public void doFilter(Request request, Response response) { request.setRequestStr(request.getRequestStr().replace("帅", "*") + "+++Sensitive"); response.setResponseStr(response.getResponseStr() + "---Sensitive"); }}//下面这个类用来把“我”替换为“你”,在请求字符串后加上"+++Word",在回应字符串上加上后缀"---WordFilter"public class WordFilter implements Filter { public void doFilter(Request request, Response response) { request.setRequestStr(request.getRequestStr().replace("我", "你") + "+++Word"); response.setResponseStr(response.getResponseStr() + "---Word"); }}同样的,我们创建一个ChainFilter来动态保存一组Filter(参考(上)中的思想),如下:
public class FilterChain implements Filter { List<Filter> filters = new ArrayList<Filter>(); public FilterChain addFilters(Filter mf) { this.filters.add(mf); return this; } public void doFilter(Request request, Response response) { for(Filter f : filters) { f.doFilter(request, response); } }}目前的任务基本完成,我们来试一试:
public class Main { public static void main(String[] args) { Request clientRequest = new Request(); Response hostResponse = new Response(); clientRequest.setRequestStr("大家好,:),我很帅"); hostResponse.setResponseStr("response!"); FilterChain fc = new FilterChain(); fc.addFilters(new FaceFilter()); fc.addFilters(new SensitiveFilter()); fc.addFilters(new WordFilter()); fc.doFilter(clientRequest, hostResponse); System.out.println(clientRequest.getRequestStr()); System.out.println(hostResponse.getResponseStr()); }}运行之后,得到如下结果:
大家好,^-^,你很*+++Face+++Sensitive+++Wordresponse!---Face---Sensitive---Word结果似乎是正确的,然而我们会发现,在发送请求的过程中,确实没有问题,但是在回应时真的是这么回事吗?让我们会想一下堆栈就不难发现我们这个逻辑是有问题的,正确的请求顺序是Face->Sensitive->Word,那么回应的时候显然应该是Face<-Sensitive<-Word。 为什么会出现这样的问题?回看代码就知道,在每一个具体的Filter中的doFilter这个方法中,我们对请求的进行过滤之后,就立马采取相关的步骤对回应也开始进行了过滤操作,这明显是不符合实际的。怎么做呢? 我们先看代码: 首先,我们修改原来的Filter接口中的方法,增加一个FilterChain fc:
public interface Filter { void doFilter(Request request, Response response, FilterChain fc);}这样做的目的是为了每次都把当前这个FilterChain放入到该方法中。再通过一个设置在FilterChain中的index的变化,我们就能轻易的知道这个目前运行到了这个FilterChain里面的哪一个Filter了,就先下面这样:
private int index = 0;//添加index作为指示运行到了哪个Filter//修改doFilter方法,依次取出fc的每一个Filter进行过滤处理 public void doFilter(Request request, Response response, FilterChain fc) { if(index == filters.size()) return; Filter f = filters.get(index); index ++; f.doFilter(request, response, fc); }最关键的一步就是我们已更改如何来使用这个doFilter方法呢? 在最开始没有进行修改以前,我们是直接通过for-each方式来进行对每个Filter提取使用其中的doFilter,然而现在的代码在我们修改后只能每次提取index位置的Filter。那么,很容易想到,我们设置这个FilterChain参数的意义了,就是把自己传进去继续调用FilterChain中的doFilter方法,进行进入递归,如下所示:
public class FaceFilter implements Filter { public void doFilter(Request request, Response response, FilterChain fc) { request.setRequestStr(request.getRequestStr().replace(":)", "^-^") + "+++Face"); fc.doFilter(request, response, fc); response.setResponseStr(response.getResponseStr() + "---Face"); }}//其他的两个Filter类似这样处理在上述这样操作以后,只需修改原来的main方法中doFilter方法,把参数添加进去就可以了:
fc.doFilter(clientRequest, hostResponse, fc);执行查看结果:
大家好,^-^,你很*+++Face+++Sensitive+++Wordresponse!---Word---Sensitive---Face没有问题。 心得 在本例中,主要用到了递归的思想,同时再一次结合了责任链的性质,每次都把自己这个FilterChain传入到自己的doFilter方法,因为其本身拥有一个Filter的List,只需要通过相关的index访问每一个Filter。 本例思路就是,在执行了当前Filter对请求Str进行操作以后,不急着进行对应答Str,而是通过递归进入doFilter方法然后获取下一个Filter,直到所有的Filter都对请求Str进行了操作以后,得到index == filters.size(),然后在return到上一层中去,直到回到最开始的那一层。(核心就是递归)
新闻热点
疑难解答