文档章节

设计模式之责任链(ChainOfResponsibility)

_-Leon-_
 _-Leon-_
发布于 2014/06/11 17:19
字数 1349
阅读 2462
收藏 11

#责任链(ChainOfResponsibility)

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

问题

public class TestMain {
public static void main(String[] args) {
    String str = "你好:),这句话中有敏感词汇,需要处理。<script>,敏感!";
    MsgProcessor pro = new MsgProcessor();
    pro.setMsg(str);
    str = pro.processor();---
    System.out.println(str);
}
}

另一个类:

public class MsgProcessor {
private String msg;
public String getMsg() {
    return msg;
}
public void setMsg(String msg) {
    this.msg = msg;
}

public String processor(){
    String content = "";
    if(null != msg && !("").equals(msg.trim())){
        content = msg.replace("<", "{")
        .replace(">", "}");
        
        content = content.replace("敏感", "");
        content = content.replace(":)", "^V^");
    }
    return content;
}  
}

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

使用接口来剥离行为

代码修改为:

public String processor(){
    if(null != msg && !("").equals(msg.trim())){
        msg = new HTMLFilter().doFilter(msg);
        msg = new SmileFilter().doFilter(msg);
        msg = new SensitivityFilter().doFilter(msg);
    }
    return msg;
}

这样还是不够灵活,直接在 ** MsgProcessor ** 类中添加一个数组来保存过滤器,然后在 ** processor** 方法中进行多次调用:

修改为:

public String processor(){
    if(null != msg && !("").equals(msg.trim())){
        for(Filter f : filters){
            msg = f.doFilter(msg);
        }
    }
    return msg;
}

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

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

新的问题

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

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

代码修改为:

MsgProcessor.java :

public class MsgProcessor {
private String msg;

private 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 processor(){
    return fc.doFilter(msg);
}
}

FilterChain.java:

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

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

public String doFilter(String str){
    if(null != str && !("").equals(str.trim())){
        for(Filter f : filters){
            str = f.doFilter(str);
        }
    }
    return str;
}
}

TestMain.java

public class TestMain {
public static void main(String[] args) {
    String str = "你好:),这句话中有敏感词汇,需要处理。<script>,敏感!";
    MsgProcessor mp = new MsgProcessor();
    mp.setMsg(str);
    FilterChain fc = new FilterChain();
    fc.addFilter(new HTMLFilter())
    .addFilter(new SmileFilter())
    .addFilter(new SensitivityFilter());
    mp.setFc(fc);
    str = mp.processor();
    System.out.println(str);
}
}

写到这里,还是没有解决我们的问题,怎样灵活合并过滤器链呢? 很简单,我们可以将过滤器链这个类,当作一个很大的过滤器来处理,这样就可以了。让** FilterChain **也实现Filter接口,这样就解决了这个问题!完成这一步,就已经有了责任链模式的味道了!

思考实际开发中的问题

在实际开发中,我们见过的过滤器都能进行双向的处理,也就是说,能处理request和response,而且是先挨着处理request,然后再反向处理response,这又是怎么实现的呢? 过滤器链图

定义一个Request和Response,在实际的web容器中,容器会帮助我们生成这两个对象,而且在其中封装了很多的东西,在这里,只是模拟,只需简单定义就可以了。

Request.java

public class Request {
private String requestStr;
public String getRequestStr() {
    return requestStr;
}
public void setRequestStr(String requestStr) {
    this.requestStr = requestStr;
}
}

Response.java

public class Response {
private String responseStr;
public String getResponseStr() {
    return responseStr;
}
public void setResponseStr(String responseStr) {
    this.responseStr = responseStr;
}
}

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

Filter.java

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

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

Filter.java

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

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

FilterChain.java

public class FilterChain implements Filter {
private List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
public FilterChain addFilter(Filter filter){
    this.filters.add(filter);
    return this;
}
@Override
public void doFilter(Request request, Response response,
        FilterChain filterChain) {
    if(index >= filters.size()) return;
    Filter f = filters.get(index);
    index++;
    f.doFilter(request, response, filterChain);
}
}  

HTMLFilter.java

public class HTMLFilter implements Filter {
@Override
public void doFilter(Request request, Response response,
        FilterChain filterChain) {
    String str = request.getRequestStr();
    System.out.println(str);
    filterChain.doFilter(request, response, filterChain);
    String resStr = response.getResponseStr();
    System.out.println(resStr);
}
}  

现在来看,每个过滤器都持有过滤器链,在处理完request后,调用下一个过滤器,由于方法是栈结构,这样就会形成一个过滤器栈,拥有栈的数据结构特点。这也是为什么Struts在配置多个拦截器的时候,成为拦截器栈的原因。 由于栈的数据特点,就能达到我们想要的特点,按照过滤器的次序,依次处理完request,然后再反向依次处理response。这就是责任链模式在实际开发中的使用。

© 著作权归作者所有

_-Leon-_
粉丝 12
博文 17
码字总数 34045
作品 0
朝阳
部门经理
私信 提问
Tomcat 系统架构与设计模式_ 设计模式分析

门面设计模式 门面设计模式在 Tomcat 中有多处使用,在 Request 和 Response 对象封装中、Standard Wrapper 到 ServletConfig 封装中、ApplicationContext 到 ServletContext 封装中等都用到...

lvzjane
2014/11/03
86
0
设计模式知识汇总(附github分享)

写在前面 主要内容 为了更系统的学习设计模式,特地开了这样一个基于Java的设计模式【集中营】,都是笔者在实际工作中用到过或者学习过的一些设计模式的一些提炼或者总检。慢慢地初见规模,也...

landy8530
2018/10/10
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
281
0
Dubbo源码分析(2),Dubbo中采用的设计模式

1、工厂模式 ServiceConfig中有个字段,代码是这样的: Dubbo里有很多这种代码。这也是一种工厂模式,只是实现类的获取采用了jdkspi的机制。这么实现的优点是可扩展性强,想要扩展实现,只需...

郑加威
2018/03/18
193
0
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
2018/11/06
184
0

没有更多内容

加载失败,请刷新页面

加载更多

最好的重试是指数后退和抖动

1. 概述 在本教程中,我们将探讨如何使用两种不同的策略改进客户端重试:指数后退和抖动。 2. 重试 在分布式系统中,多个组件之间的网络通信随时可能发生故障。 客户端应用程序通过实现重试来...

liululee
9分钟前
3
0
聊一聊大厂内部的安全管理机制

工作了两个月了体会到了很多之前做外包小项目没有的东西,不得不说大厂的还是有自己一套的完善的体制,不会像B站那样泄露自己整个后台的源码这种事情发生。 电脑办公 比如说在使用电脑办公这...

gzc426
36分钟前
4
0
如何利用deeplearning4j中datavec对图像进行处理

NativeImageLoader Labelloader = new NativeImageLoader(112, 112, 3,new FlipImageTransform(-1)); 一、导读 众所周知图像是有红绿蓝三种颜色堆叠而成,利用deeplearning对图像处理,必须把...

冷血狂魔
38分钟前
7
0
1. Context - React跨组件访问数据的利器

《react-router-dom源码揭秘》系列 2. React-Router的基本使用 3. react-router-dom源码揭秘 - BrowserRouter Context提供了一种跨组件访问数据的方法。它无需在组件树间逐层传递属性,也可以...

前端老手
48分钟前
5
0
Docker入门实战--开篇,为什么要使用Docker

前面Thrift文章中,我曾经介绍过我为什么要用Thrift。Docker的使用却是不一样的。纯属没事找事,因为我现在一个人的团队,项目只要一个project目录足够了! 那我何苦要用Docker呢 各位且听听...

后天的奇点
48分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部