责任链模式在设计模式里边属于比较难的设计模式,主要用于对一个对象进行一系列的操作,每个操作相互独立。这一系列的操作组成了一个操作链,每个操作都有其具体的职责,即是一个责任链。

UML图如下

先用一个简单的例子来体验一下责任链模式,假设有个程序需要接收一个消息,但是这个消息需要进行过滤,比如HTML,JS的转义,敏感字符的替换等。

定义一个消息类,只有消息这一个属性;定义一个过滤器,只有过滤这一个方法,然后给出三个实现,分别用于HTML,JS和敏感字符的过滤。

public class Msg {private String text;public String getText() {return text;}public void setText(String text) {this.text = text;}@Overridepublic String toString() {return text;}
}public interface Filter {/*** 过滤方法* @param msg* @return true:继续执行; false: 不继续执行*/boolean doFilter(Msg msg);
}public class HTMLFilter implements Filter {@Overridepublic boolean doFilter(Msg msg) {String text = msg.getText();text = text.replaceAll("<", "[");text = text.replaceAll(">", "]");msg.setText(text);return true;}}public class JSFilter implements Filter {@Overridepublic boolean doFilter(Msg msg) {String text = msg.getText();msg.setText(text.replaceAll("javascript", "cdth"));return true;}}public class SensitiveFilter implements Filter{private final String sensitiveText = "996" ;@Overridepublic boolean doFilter(Msg msg) {String text = msg.getText();msg.setText(text.replaceAll(sensitiveText, "955"));return false;}}

责任链模式最主要的地方就是实现责任链,我们可以定义一个类,维护一个过滤器的集合,在调用过滤方法的时候把集合里的过滤器遍历,依次调用其自身的过滤方法,且根据返回值来判断过滤器链要不要继续往下执行。这里可以看到,过滤器链本身也实现了Filter接口,这说明我们可以把该过滤器链接到其他的过滤器链的后边。

public class FilterChain implements Filter {private List<Filter> filters = new ArrayList<>();public FilterChain addFilter(Filter filter) {filters.add(filter);return this;}@Overridepublic boolean doFilter(Msg msg) {for (Filter filter : filters) {if(!filter.doFilter(msg)) {return false;}}return true;}}

测试一下。

public class Main {public static void main(String[] args) {Msg msg = new Msg();msg.setText("<p>i love javascript</p><p>i hate 996</p>");FilterChain chain = new FilterChain();chain.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter()).addFilter(new JSFilter());chain.doFilter(msg);System.out.println(msg);}
}

在JAVAEE 中,过滤器Filter接口其实就是一种责任链模式的实现,简单写个DEMO来模仿一下Filter的原理。

首先我们需要ServletRequest,ServletResponse,和FilterChain 三个对象,其中ServletRequest,ServletResponse只有一个属性Body,FilterChain对象暂时没有任何东西。

public class ServletRequest {private String body;public String getBody() {return body;}public void setBody(String body) {this.body = body;}@Overridepublic String toString() {return body;}
}public class ServletResponse {private String body;public String getBody() {return body;}public void setBody(String body) {this.body = body;}@Overridepublic String toString() {return body;}
}public class FilterChain {
}

然后,我们需要一个Filter接口,用于对ServletRequest和ServletResponse进行过滤,且可以顺着过滤器链一直往下执行。所以Filter接口需要三个参数ServletRequest,ServletResponse和FilterChain。其中让过滤器开始工作的入口是过滤器链提供的,所以FilteChain需要有一个方法(public void doFilter(ServletRequest request, ServletResponse response) )来让过滤器链中的过滤器开始工作。再添加三个Filter接口的实现,同样是对HTML,JS,敏感词的过滤。

public interface Filter {void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);}public class FilterChain {public void doFilter(ServletRequest request, ServletResponse response) {}}public class HTMLFilter implements Filter{@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// start process requestString body = request.getBody();body = body.replaceAll("<", "[");body = body.replaceAll(">", "]");request.setBody(body + " --html filter");// next filter of chain start process request chain.doFilter(request, response);// request process finished, start process responseresponse.setBody(response.getBody() + " --html filter");}}public class JSFilter implements Filter{@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// start process requestrequest.setBody(request.getBody().replaceAll("javascript", "cdth") + " --js filter");// next filter of chain start process request chain.doFilter(request, response);// request process finished, start process responseresponse.setBody(response.getBody() + " --js filter");}}public class SensitiveFilter implements Filter{@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// start process requestrequest.setBody(request.getBody().replaceAll("996", "955") + " --sensitive filter");// next filter of chain start process request chain.doFilter(request, response);// request process finished, start process responseresponse.setBody(response.getBody() + " --sensitive filter");}}

可以看到每个过滤器的实现都是先处理request,再交给链条中的下一个过滤器去处理request,然后再处理response。因为JAVAEE标准就是对request的处理和对response的处理,其顺序是正好相反的;例如,处理request的顺序是HTMLFilter,JSFilter,SensitiveFilter,那么处理repsonse的顺序就是SensitiveFilter,JSFilter,HTMLFilter。其实Spring MVC的拦截器调用preHandle和postHandle的顺序,也是这样的。

现在需要做的就是实现FilterChain,首先肯定需要把过滤器都存起来,所以需要集合和addFilter方法。重点就在于doFilter方法,为了保证上述的顺序,需要有一个index来保证当前使用的过滤器。

以下是FilterChain的完整实现。

public class FilterChain {private List<Filter> filters = new ArrayList<>();private int index;public FilterChain addFilter(Filter filter) {filters.add(filter);return this;}public void doFilter(ServletRequest request, ServletResponse response) {if(index < filters.size()) {Filter filter = filters.get(index);index++;filter.doFilter(request, response, this);}}}

测试一下。

public class Main {public static void main(String[] args) {ServletRequest request = new ServletRequest();request.setBody("<p>i love javascript</p><p>i hate 996</p>");ServletResponse response = new ServletResponse();response.setBody("response");FilterChain chain = new FilterChain();chain.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter()).addFilter(new JSFilter());chain.doFilter(request,response);System.out.println("---------request-----------");System.out.println(request.getBody());System.out.println("---------response-----------");System.out.println(response.getBody());}}

运行之后,程序确实如期的执行。

现在再回到Filter上来,虽然我们把三个过滤器都添加进了过滤器链,但是如果我其中的一个过滤器没有去让链条往下执行,那么链条实际上会在这个过滤器的地方“递归回去”。

现在 SensitiveFilter 处于链条中的第二个位置,如果我把chain.doFilter(request, response)注释掉,那么过滤器链就会在他这里终止不会去找下一个过滤器即JSFilter。

public class SensitiveFilter implements Filter{@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// start process requestrequest.setBody(request.getBody().replaceAll("996", "955") + " --sensitive filter");// next filter of chain start process request //chain.doFilter(request, response);// request process finished, start process responseresponse.setBody(response.getBody() + " --sensitive filter");}}

JAVA设计模式之责任链模式相关推荐

  1. Java设计模式作业-责任链模式

    Java设计模式作业-责任链模式:Web过滤器 文章目录 前言 一.类图 二.代码及测试结果 1.Trouble类 2.Support类 3.CharSupport类 4.TypeTransformS ...

  2. Java设计模式系列--责任链模式(应用)

    原文网址:Java设计模式系列--责任链模式(应用)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java设计模式中的责任链模式的一些使用场景. 责任链模式的好处 符合单一职责原则 每个功能 ...

  3. JAVA设计模式之责任链模式(职责链模式)

    转自JAVA设计模式之责任链模式(职责链模式)​​​​​​​ 责任链/职责链(Chain of Responsibility)模式的定义 为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理 ...

  4. Java设计模式之责任链模式(简单易懂)

    前言: 责任链模式(Chain of Responsibility): 使多个对象都有机会处理同一请求,从而避免请求的发送者和接受者之间的耦合关系,每个对象都是一个处理节点,将这些对象连成一条链,并沿 ...

  5. 轻松学习Java设计模式之责任链模式

    我们的态度是:每天进步一点点,理想终会被实现. 前言 设计模式,可能很多人都是看到代码知道怎么回事,但是离开代码再让其说出来,估计就有点含糊其词了,包括我自己在内.Android中其实用到的设计模式也 ...

  6. Java设计模式之责任链模式(二)

    所有设计模式传送门 本文将一起介绍学习下设计模式之责任链模式.责任链模式是指使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有 ...

  7. 折腾Java设计模式之责任链模式

    责任链模式 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计 ...

  8. Java 设计模式之责任链模式实现的三种方式

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 The worst way to miss someone is to be ...

  9. 用王者荣耀来理解java设计模式之责任链模式

    在王者荣耀商城中,玩家可以参与夺宝抽奖.夺宝抽奖分两种,一种是积分抽奖,另一种是钻石抽奖:在平常,两种夺宝抽奖方式均可以通过60钻石/积分抽奖一次,或者通过270钻石/积分连续抽奖5次:其中,当钻石夺 ...

最新文章

  1. 软件配置管理(Software Configuration Management,SCM)
  2. 解救人质的android游戏,黑帽子解救人质全关卡解锁版 1.03 安卓版
  3. think php自增,thinkphp5分表自增ID解决方案
  4. Jmeter基础(二)
  5. 万级K8s集群背后etcd稳定性及性能优化实践
  6. OpenFOAM边界类型(终极详细介绍)
  7. 查看node的位置_升级Node版本RN项目运行报错cb.apply is not a function
  8. 学习 shell脚本之前的基础知识
  9. svn添加用户.sh
  10. mysql 本地登录失败 - 已授权
  11. 一种在智能对话中实现上下文功能的方法
  12. linux 占用缓存前10_Linux安装软件时很多人会遇到这个报错,如何解决?
  13. json解析和字符串解析_高效创建和解析定界字符串
  14. 转:Python正则表达式操作指南
  15. 阿里云2017财年:营收66.63亿 同比增长121%
  16. 机械工程学专业词汇英语翻译
  17. 使用python获取win10锁屏照片
  18. 分享830个蜘蛛IP段(分析1G日志得)
  19. 容器高度或者宽度的获取方式
  20. Ubuntu换源操作+vim的下载

热门文章

  1. JAVA反射----->看这篇就够了
  2. FFmpeg MP4 m3u8 视频 相互转换
  3. openstack 学习笔记 虚拟机的基础安装sql glance nova keystone 。。。。。
  4. 证件类型、证件号码、性别、出生日期校验(身份证、户口簿、港澳居民居住证、台湾居民居住证、港澳居民来往内地通行证、台湾居民来往大陆通行证、境外永久居住证、外国人永久居留身份证、护照、其他)
  5. OR值的意义和计算公式,和95% CI
  6. JS前端加密、JAVA后端解密详解
  7. android java pbo_Android OpenGL ES 3.0 PBO而不是glReadPixels()
  8. 2014婚纱照8大流行风格大揭密
  9. beecloud轻松实现支付
  10. microbit题目和规范文档