您的位置:首页 > 其它

责任链模式

2012-04-30 13:34 232 查看
简单介绍一下什么是责任链模式?

如果您了解Servlet规范的话,一定会知道Filter;如果您使用过Struts2的话,一定清楚无处不在的interceptor。责任链模式顾名思义,对一个请求设计出一个链状的处理流程,处于链条上的每个类都可以处理这个请求,或者放弃对请求的处理然后交给链条上的下一个类。

如果你没有学过Filter或者interceptor,没关系,给出Filter的原理图你就会发现其实它们很简单

原理图:下面是没有使用Filter的web应用



下面是使用了Filter的web应用



当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据检查或改动,并以此通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据时间让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。

实例:来源于马士兵老师的视频,这个实例简单地模拟了Servlet的Filter功能

案例1:实现了将Msg由客户端向服务器端的过滤,如下图清晰地解析了程序的执行过程



Main类:调用MsgProcessor类的process()方法完成对客户端信息的过滤处理

public class Main {

public static void main(String[] args) {
String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter())
.addFilter(new SesitiveFilter())
;
FilterChain fc2 = new FilterChain();
fc2.addFilter(new FaceFilter());

fc.addFilter(fc2);
mp.setFc(fc);
String result = mp.process();
System.out.println(result);
}

}


MsgProcessor类:中间类,实际上是调用FilterChain的doFilter()方法

public class MsgProcessor {
private String msg;

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

public FilterChain getFc() {
return fc;
}

public void setFc(FilterChain fc) {
this.fc = fc;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public String process() {

return fc.doFilter(msg);

}
}


定义接口类Filter

public interface Filter {
String doFilter(String str);
}


3个具体实现上面接口的类

SesitiveFilter类

public class SesitiveFilter implements Filter {

@Override
public String doFilter(String str) {
//process the sensitive words
String r = str.replace("被就业", "就业")
.replace("敏感", "");

return r;
}

}


FaceFilter类

public class FaceFilter implements Filter {

@Override
public String doFilter(String str) {
return str.replace(":)", "^V^");
}

}


HTMLFilter类

public class HTMLFilter implements Filter {

@Override
public String doFilter(String str) {
//process the html tag <>
String r = str.replace('<', '[')
.replace('>', ']');
return r;
}

}


FilterChain类:完成对Filter类的批量处理

import java.util.ArrayList;
import java.util.List;

public class FilterChain implements Filter {
List<Filter> filters = new ArrayList<Filter>();

public FilterChain addFilter(Filter f) {
this.filters.add(f);
return this;
}

public String doFilter(String str) {
String r = str;
for(Filter f: filters) {
r = f.doFilter(r);
}
return r;
}
}


上面的案例只能实现单一方向的过滤,而实际上,在web应用中,客户端和服务器端的响应通常是这样的:

同一个Filter既对客户端发往服务器端的消息进行过滤处理,又对服务器端发往客户端的消息进行过滤处理。

案例2:如下图清晰地解析了程序的执行过程



A B C

现在就真正在模拟Servlet的Filter功能或Struts的Intecerpter功能了,这里我们用Request对象封装客户端的请求信息,用Response对象封装服务器端反馈回来的信息。

因为Filter是在FilterChain中,信息的过滤处理类似于栈的结构,比如在客户端往服务器端处理的过程中,是排在前面A的Filter先处理,排在后面的c后处理;而在服务器端往客户端处理过程中,是排在后面的C先处理,排在前面的A后处理,怎么处理呢?

可以这样考虑:将FilterChain的引用传递给Filter,因为FilterChain中包含了排列好了的Filter,若是信息被过滤器A执行处理,将获得FilterChain对象,信息将会按照FilterChain中的Filter的顺序执行下去

Request对象:封装客户端发送的信息

public class Request {
String requestStr;

public String getRequestStr() {
return requestStr;
}

public void setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}


Response对象:封装服务器端反馈的信息

public class Response {
String responseStr;

public String getResponseStr() {
return responseStr;
}

public void setResponseStr(String responseStr) {
this.responseStr = responseStr;
}

}


接口类: Filter

public interface Filter {
void doFilter(Request request, Response response, FilterChain chain);
}


实现上述接口的两个类:

SesstiveFilter:处理敏感信息

public class SesitiveFilter implements Filter {

@Override
public void doFilter(Request request, Response response, FilterChain chain) {
request.requestStr = request.requestStr.replace("被就业", "就业")
.replace("敏感", "") + "---SesitiveFilter()";
chain.doFilter(request, response, chain);
response.responseStr += "---SesitiveFilter()";
}

}


HTMLFilter:处理HTML标签

public class HTMLFilter implements Filter {

@Override
public void doFilter(Request request, Response response, FilterChain chain) {
//process the html tag <>
request.requestStr = request.requestStr.replace('<', '[')
.replace('>', ']') + "---HTMLFilter()";
chain.doFilter(request, response, chain);
response.responseStr += "---HTMLFilter()";
}

}


FilterChain:下面的着红色的代码解决了Response对象逆向被Filter处理

public class FilterChain implements Filter {
List<Filter> filters = new ArrayList<Filter>();
int index = 0;

public FilterChain addFilter(Filter f) {
this.filters.add(f);
return this;
}

@Override
public void doFilter(Request request, Response response, FilterChain chain) {
if(index == filters.size()) return ;

Filter f = filters.get(index);
index ++;
f.doFilter(request, response, chain);
}
}


测试代码:

public class Main {

/**
* 模拟Servlet中Request和Response的调用过程
*/
public static void 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())
;

fc.doFilter(request, response, fc);
System.out.println(request.getRequestStr());
System.out.println(response.getResponseStr());
}

}


下面是测试结果:

大家好:),[script],,就业,网络授课没感觉,因为看不见大家伙儿---HTMLFilter()---SesitiveFilter()
response---SesitiveFilter()---HTMLFilter()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: