职责链设计模式

前言

职责链,通俗地讲就是把责任处理对象连城一条链,这样当一个处理对象不能及时处理的时候就会交给下一个处理对象直到被处理为止。就好比生活中,我们有事向学校请假,得找班主任签字同意,然后有些时候需要院里签字,甚至教务处,最后将假条交给同学,最后在给相应授课老师,可能这个例子还不太准确,但是总之经过一些列流程,最后才会处理。

当然,在程序中,最常见的就是过滤关键字了,首先模拟一下非web下的责任链

首先定义一个过滤接口

1
2
3
public interface Filter {
String doFilter(String str);
}

接下来就是各式各样的过滤字
敏感字过滤

1
2
3
4
5
6
7
8
9
10
11
12
public class SesitiveFilter implements Filter {
@Override
public String doFilter(String str) {
//第一个参数是非法字符,第二个参数是被替换的字符
String r = str.replace("瞎子", "李青")
.replace("小学僧", "盲僧");
return r;
}
}

过滤html标签

1
2
3
4
5
6
7
8
9
10
11
public class HTMLFilter implements Filter {
@Override
public String doFilter(String str) {
//<>被替换成[]
String r = str.replace('<', '[')
.replace('>', ']');
return r;
}
}

过滤链:将过滤器串成一个链,并保存过滤后的字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FilterChain implements Filter {
//保存所有的具体过滤器
List<Filter> filters=new ArrayList<Filter>();
//过滤器串成链
public FilterChain addFilter(Filter f)
{
this.filters.add(f);
return this;
}
//返回过滤后的字符
@Override
public String doFilter(String str) {
String r=str;
for(Filter f:filters){
r=f.doFilter(r);
}
return r;
}
}

测试:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
String msg = "因为一个英雄而爱上了lol,他就是瞎子,虽然我是小学僧,但是我还是只坚信我的<我的信仰>英雄!!";
FilterChain fc = new FilterChain();
fc.addFilter(new SesitiveFilter())
.addFilter(new HTMLFilter());
String result=fc.doFilter(msg);
System.out.println(result);
}

输出结果:

因为一个英雄而爱上了lol,他就是李青,虽然我是盲僧,但是我还是只坚信我的[我的信仰]英雄!!

Web下责任链

当然一般情况下,都是过滤web环境下的字符,大概思路跟非web下差不多

首先需要建立request和response对象,即接收和响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Request {
String requestStr;
public String getRequestStr() {
return requestStr;
}
public void setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}
public class Response {
String responseStr;
public String getResponseStr() {
return responseStr;
}
public void setResponseStr(String responseStr) {
this.responseStr = responseStr;
}
}

然后是Filter接口

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

紧接着是filterchain类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class FilterChain implements Filter {
//存放各种filter
List<Filter> filters = new ArrayList<Filter>();
//控制filter的索引
int index = 0;
//添加filter
public FilterChain addFilter(Filter f) {
this.filters.add(f);
return this;
}
//filter链,特别注意这里有一个迭代,与具体filter里的迭代相呼应
//主要是依次先取出request的接受字符过滤,然后在倒叙依次取完response的响应过滤,而这恰恰是struts2框架原理的核心,当然spring mvc(直接基于servlet)也类似,都是基于拦截或者过滤实现的
@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);
}
}

然后就是具体的filter了(这里就是web中的真实拦截顺序了)

1
2
3
4
5
6
7
8
9
10
11
12
public class SesitiveFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
// TODO Auto-generated method stub
request.requestStr = request.requestStr.replace("瞎子", "李青")
.replace("小学僧", "盲僧") ;
chain.doFilter(request, response, chain);
response.responseStr += "SesitiveFilterresponse";
}
}

另一个filter

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HTMLFilter implements Filter {
@Override
public void doFilter(Request request, Response response,FilterChain chain) {
// TODO Auto-generated method stub
request.requestStr = request.requestStr.replace('<', '[')
.replace('>', ']') ;
chain.doFilter(request, response, chain);
response.responseStr += "HTMLFilterresponse";
}
}

先附一张structs2原理图,来对比一下上述过滤过程
Alt text
主要关注action invocation中部分

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {
String msg = "因为一个英雄而爱上了lol,他就是瞎子,虽然我是小学僧,但是我还是只坚信我的<我的信仰>英雄!!";
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());
}

结果:

因为一个英雄而爱上了lol,他就是李青,虽然我是盲僧,但是我还是只坚信我的[我的信仰]英雄!!
response–SesitiveFilterresponse–HTMLFilterresponse

最后归纳一下责任链设计模式的一般形式
Alt text
分别为客户端、处理者和具体处理者

热评文章