设计模式之责任链(ChainOfResponsibility)

责任链(ChainOfResponsibility)

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

问题

1public class TestMain {
2public 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}

另一个类:

01public class MsgProcessor {
02private String msg;
03public String getMsg() {
04    return msg;
05}
06public void setMsg(String msg) {
07    this.msg = msg;
08}
09
10public 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}

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

使用接口来剥离行为

代码修改为:

1public 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** 方法中进行多次调用:

修改为:

1public 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}

这样调整后,所有的过滤器都起作用了,添加起来更加灵活一些,并且过滤器的执行顺序也是可控的。

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

新的问题

如果本来已经存在一个过滤器链条了,我想把一些新的过滤器链加进去,并且加入的顺序可以随意控制(随意组合任意的过滤器链条),该怎么办呢?

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

代码修改为:

MsgProcessor.java :

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

FilterChain.java:

01public class FilterChain {
02List<Filter> filters = new ArrayList<Filter>();
03
04public FilterChain addFilter(Filter filter){
05    filters.add(filter);
06    return this;
07}
08
09public 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

01public class TestMain {
02public 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

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

Response.java

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

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

Filter.java

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

别的代码跟着这个接口一起改就可以了,但是你会发现,还是不能实现我们想要的效果,这个时候需要一些编程的手法,我们继续修改Filter接口:

Filter.java

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

为什么要这样修改,因为只有这样才能把链条握在每一个过滤器手中,有了链条,就可以控制链条了:

FilterChain.java

01public class FilterChain implements Filter {
02private List<Filter> filters = new ArrayList<Filter>();
03private int index = 0;
04public FilterChain addFilter(Filter filter){
05    this.filters.add(filter);
06    return this;
07}
08@Override
09public 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

01public class HTMLFilter implements Filter {
02@Override
03public 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。这就是责任链模式在实际开发中的使用。


转载于:https://my.oschina.net/u/1048681/blog/288422

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值