今天分享一下,设计模式中的责任链模式,其余的不过多叙述。


思路

在正式接触责任连之前,我们可以想象到的应该是一个链,链表?要处理一件事需要一个链似得?其实答案差不多就是这样。设计模式也都是从朴素的思维中经过一系列的总结得到的。下面来谈一谈责任链的进化之路。

来源

责任链也是从实际的开发中不断升华得到的一个“套路”,这也是称之为“模式”的原因了。比如说,我们现在要对用户上传的数据进行过滤。要实现这样的一个功能,我们首先想到的可能是下面这样的。

// 待处理的用户的输入数据
        String message = "<script>while(1){alert('HaHa,敏感词,替换词')</script>";

         String result = message.replaceAll("<","[");
         result = result.replaceAll(">","]");

        System.out.println("未被处理的数据为:" + message);
        System.out.println("经过处理的数据为:" + result);

很简单了吧,但是想一想,这样真的够了吗?

其实String类的设计就是一个链的模式,这点我们可以从replaceAll方法中看出一点端倪。

加大点难度

现在假如说添加了一个更加高级点的功能,那就是实现对HTML的代码的转义,敏感词的过滤,替换词的替换等等。那么如果我们还这样写的话,这个方法体就会变的很大,而且不容易进行维护。而根据面向对象的思维,我们不难想到抽象出一个接口,要想实现哪种功能,就直接让其实现这个接口完成相应的业务逻辑就好了嘛。

下面我们就来看看这种实现。

首先是接口:Filter.java

package ResponsibilityChain;

public interface Filter {

    public String doFilte(String message);

}

HTMLFilter.java

package ResponsibilityChain;

/**
 * HTML filter utility.
 *
 * 但是也添加了一些修改内容
 *
 * @author Craig R. McClanahan
 * @author Tim Tye
 */
public final class HTMLFilter implements Filter{

    /**
     * Filter the specified message string for characters that are sensitive in
     * HTML. This avoids potential attacks caused by including JavaScript codes
     * in the request URL that is often reported in error messages.
     *
     * @param message
     *            The message string to be filtered
     */
    public String doFilte(String message) {

        if (message == null)
            return (null);

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());

    }

}

SesitiveFilter.java

package ResponsibilityChain;

public final class SesitiveFilter implements Filter {

    @Override
    public String doFilte(String message) {

        // 正常来说应该是个词库的,对词库中的数据进行匹配,这样比较合理一些,此处为了掩饰核心思想,就简化了这个操作
        String str = message.replaceAll("敏感词", "不敏感了");
        return str;
    }

}

ReplacableFilter.java

package ResponsibilityChain;

public class ReplacableFilter implements Filter {

    @Override
    public String doFilte(String message) {
        // 正常来说应该是个词库的,对词库中的数据进行匹配,这样比较合理一些,此处为了掩饰核心思想,就简化了这个操作
        String str = message.replaceAll("替换词", "已被替换");
        return str;
    }

}

然后是一个业务逻辑的管家了,它负责接收要进行过滤的数据,并且返回处理过的数据,MyProcessor.java

package ResponsibilityChain;

public class MyProcessor {

    private String msg;

    public String getMsg() {
        return msg;
    }

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

    public String process() {
        // 调用相关的过滤器进行词汇的过滤
        HTMLFilter htmlFilter = new HTMLFilter();
        String result = htmlFilter.doFilte(msg);

        // 调用敏感词过滤器
        SesitiveFilter sesitiveFilter = new SesitiveFilter();
        result = sesitiveFilter.doFilte(result);

        ReplacableFilter replacableFilter = new ReplacableFilter();
        result = replacableFilter.doFilte(result);

        return result;
    }

}

最后来个测试吧。Main.java

package ResponsibilityChain;

public class Main {

    public static void main(String[] args) {
        // 待处理的用户的输入数据
        String message = "<script>while(1){alert('HaHa,敏感词,替换词')</script>";

         MyProcessor myProcessor = new MyProcessor();
         myProcessor.setMsg(message);
         String result = myProcessor.process();

        System.out.println("未被处理的数据为:" + message);
        System.out.println("经过处理的数据为:" + result);
    }

}

小总结

这样就可以实现我们需要的功能了,我们可以在MyProcessor类中添加我们的过滤器,完成所有我们需要的功能。但是看一下,

public String process() {
        // 调用相关的过滤器进行词汇的过滤
        HTMLFilter htmlFilter = new HTMLFilter();
        String result = htmlFilter.doFilte(msg);

        // 调用敏感词过滤器
        SesitiveFilter sesitiveFilter = new SesitiveFilter();
        result = sesitiveFilter.doFilte(result);

        ReplacableFilter replacableFilter = new ReplacableFilter();
        result = replacableFilter.doFilte(result);

        return result;
    }

这段代码,总是感觉有点冗余,给人的感觉就是有点笨重了。下面我们就来解决一下这个问题。

责任链前身

为了解决上面的代码过于冗余,下面引入了责任链的前身,那就是使用一个数组保存我们所有的Filter的实现类,用于管理我们的过滤任务。我们只需要在MyProcessor类中进行修改即可。

如下,MyProcessor2.java

package ResponsibilityChain;

public class MyProcessor2 {

    Filter[] filters = { new HTMLFilter(), new SesitiveFilter(), new ReplacableFilter() };

    private String msg;

    public String getMsg() {
        return msg;
    }

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

    public String process() {
        String result = msg;

        for (Filter f : filters) {
            result = f.doFilte(result);
        }

        return result;
    }

}

测试一下:

package ResponsibilityChain;

public class Main2 {

    public static void main(String[] args) {
        // 待处理的用户的输入数据
        String message = "<script>while(1){alert('HaHa,敏感词,替换词')</script>";

        MyProcessor2 myProcessor2 = new MyProcessor2();
        myProcessor2.setMsg(message);
        String result = myProcessor2.process();

        System.out.println("未被处理的数据为:" + message);
        System.out.println("经过处理的数据为:" + result);
    }

}

小总结:这里我们明显的可以看到使用了数组来进行管理的好处了吧,我们只需要在添加新的过滤器实现类的时候在这个数组里面就可以了。

这样看着,有点意思了吧。

责任链出山

看完了上面的代码,想必对这个业务逻辑很熟悉了吧。但是这还不是我们的责任链模式,没有体现出“链”的特点,而且假如说我们有两个这样的数组,要合作的完成过滤任务,而且是在一个完成一半的时候插入另一个数组的任务,这样的话,就比较的棘手了吧。所以下面要交给责任链来进行管理了。

FilterChain.java

package ResponsibilityChain;

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

public class FilterChain implements Filter{

    private List<Filter> filters = new ArrayList<Filter>();

    /**
     * return itself for better usage the Chain
     *
     * @param f
     * @return
     */
    public FilterChain addFilter(Filter f) {
        filters.add(f);
        return this;
    }

    public void remove(Filter f) {
        filters.remove(f);
    }

    /**
     * For the chain , it's also a chain for filter
     *
     * @param message
     *            message need to be filtered
     * @return
     */
    public String doFilte(String message) {
        String result = message;
        for (Filter f : filters) {
            result = f.doFilte(result);
        }
        return result;
    }

}

这样一来,MyProcessor也要进行修改,如MyProcessor3.java

package ResponsibilityChain;

public class MyProcessor3 {

    private FilterChain filterChain;

    public FilterChain getFilterChain() {
        return filterChain;
    }

    public void setFilterChain(FilterChain filterChain) {
        this.filterChain = filterChain;
    }

    private String msg;

    public String getMsg() {
        return msg;
    }

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

    // 此处为核心and关键
    public String process() {
        String result = msg;

        result = filterChain.doFilte(result);

        return result;
    }

}

再来测试一把,Main3.java

package ResponsibilityChain;

public class Main3 {

    public static void main(String[] args) {
        // 待处理的用户的输入数据
        String message = "<script>while(1){alert('HaHa,敏感词,替换词')</script>";

        MyProcessor3 myProcessor3 = new MyProcessor3();
        myProcessor3.setMsg(message);

        FilterChain filterChain = new FilterChain();
        // filterChain.addFilter(new HTMLFilter());
        // filterChain.addFilter(new SesitiveFilter());
        // filterChain.addFilter(new ReplacableFilter());

        myProcessor3.setFilterChain(filterChain);
        // 作为一个链的方式进行添加过滤器,这就是链式编程的好处
        filterChain.addFilter(new HTMLFilter()).addFilter(new SesitiveFilter()).addFilter(new ReplacableFilter());
        String result = filterChain.doFilte(message);
        System.out.println("未被处理的数据为:" + message);
        System.out.println("经过处理的数据为:" + result);
    }

}

这里就需要好好的来个总结了,经典的思想总是让人感叹啊。

不知道你有没有注意到在FilterChain.java中

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

这个方法就可以完成“链”的效果。返回自身,这样就可以不断的调用同样的方法,链式的完成任务。

还有FilterChain也有一个doFilte的方法,也就是说我们将完成过滤的功能从MyProcessor.java类中迁移到了FilterChain类中了。

而且实现了Filter接口的FilterChain也就可以完成添加更加自由的过滤规则了。

这就是面向对象的核心,一个对象能完成什么功能完全取决于其自身的属性。

这样我们在MyProcessor3.java中只需要调用责任链的这个过滤功能就可以了。

总结

本文从一个现实中的问题出发,从简单的朴素的思想,一步步的经过面向对象的强化以及经典的责任链思想的牵引。完成了一个简单的责任链模式的小例子。

如果细心的品味一下,肯定会有不少感触的吧。责任链模式在实际的开发过程中也是很常见的,比如说Struts2的拦截器栈等等。

The Chain Of Responsibility (1)的更多相关文章

  1. 责任链模式/chain of responsibility/行为型模式

    职责链模式 chain of responsibility 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处 ...

  2. C#设计模式系列:职责链模式(Chain of Responsibility)

    1.职责链模式简介 1.1>.定义 职责链模式是一种行为模式,为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求.将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对 ...

  3. 职责链(Chain of Responsibility)模式在航空货运中的运用实例

    设计模式这东西,基本上属于“看懂一瞬间,用会好几年”.只有实际开发中,当某一模式很好的满足了业务需求时,才会有真切的感觉.借用一句<闪电侠>中,绿箭侠教导闪电侠的台词:“不是你碰巧遇到了它 ...

  4. 深入浅出设计模式——职责链模式(Chain of Responsibility Pattern)

    模式动机 职责链可以是一条直线.一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求.链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传 ...

  5. 设计模式之美:Chain of Responsibility(职责链)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现后继者链. 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链,并沿着这条 ...

  6. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  7. 设计模式:职责链模式(Chain Of Responsibility)

    定  义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止. 结构图: 处理请求类: //抽象处理类 abs ...

  8. 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)

    责任链模式(Chain of Responsibility Pattern) 介绍为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求.将这些对象连成一条链,并沿着这条链传递该请求,直 ...

  9. 设计模式 - chain of Responsibility

    Chain of Responsibility也就是职责链模式,通过使用链式结构,使对象都有机会处理请求,从而避免请求的发送者与接受者间的耦合关系.将这些对象连成链,并沿着该链传递请求,直到有对象处理 ...

  10. [学习笔记]设计模式之Chain of Responsibility

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...

随机推荐

  1. [POI2016]Nim z utrudnieniem

    Description A和B两个人玩游戏,一共有m颗石子,A把它们分成了n堆,每堆石子数分别为a[1],a[2],...,a[n],每轮可以选择一堆石子,取掉任意颗石子,但不能不取.谁先不能操作,谁 ...

  2. [POI2006]ORK-Ploughing

    Description Byteasar想耕种他那块矩形的田,他每次能耕种矩形的一边(上下左右都行),在他每次耕完后,剩下的田也一定是矩形,每块小区域边长为1,耕地的长宽分别为m和n,不幸的是Byte ...

  3. 【BZOJ2809】【APIO2012】派遣

    Background 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. Description 在这个帮派里,有一名忍者被称之为Master.除了Master以外,每名忍者 ...

  4. 【USACO】 洞穴奶牛

    题目描述 贝西喜欢去洞穴探险.这次她去的地方由 N 个洞穴组成,编号分别是 1 到 N,1 号洞穴是出发 的起点. 洞穴之间由 M 条隧道相连,双向通行,第 i 条隧道连接 A i 和 B i .每条 ...

  5. [bzoj4868][Shoi2017]期末考试

    来自FallDream 的博客,未经允许,请勿转载,谢谢. 有n位同学,每位同学都参加了全部的m门课程的期末考试,都在焦急的等待成绩的公布.第i位同学希望在第ti天或之前得知所.有.课程的成绩.如果在 ...

  6. mysql获取某个表的所有字段名

    http://www.netingcn.com/mysql-column-name.html mysql安装成功后可以看到已经存在mysql.information_schema和test这个几个数据 ...

  7. java表达式类型的自动提升

    当一个java算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型将发生自动提升.Java定义如下的自动提升规则:1. 所有byte型.short型和char型将被提升到int型. 2. 整个 ...

  8. linux安装ftp

    安装vsftpd 1.以管理员(root)身份执行以下命令 1.  yum install vsftpd 2.设置开机启动vsftpd ftp服务 1.  chkconfig vsftpd on 3. ...

  9. pm2进阶使用

    启用集群模式 只需要在启动应用时带上i参数 pm2 start app.js -i max max:意味着PM2将自动检测可用的CPU数量和运行多个进程可以在负载均衡模式(但是不推荐使用) 或者使用j ...

  10. electron-vue 初体验

    注意事项 首先确保node和npm是最新版本 避免使用镜像(我淘宝镜像安装有报错现象) 避免window的一些坑 若上一项检查完成,我们可以继续设置所需的构建工具.使用 windows-build-t ...