-
责任链模式
2020-02-14 11:39:08责任链模式 有的时候,客户端请求发给服务器处理之前,需要进行...假如我们在论坛发表文章,那么服务端在发表或者存入数据库之前,会对文章内容进行安全检查,安全检查分为很多类,这里我们使用责任链模式来实现 ...责任链模式
有的时候,客户端请求发给服务器处理之前,需要进行一系列的预处理,每次预处理由某个对象完成(完成一定职责),一系列的对象形成了链条,这就是责任链模式(Chain of Responsibility Pattern)
假如我们在论坛发表文章,那么服务端在发表或者存入数据库之前,会对文章内容进行安全检查,安全检查分为很多类,这里我们使用责任链模式来实现
- 我们写一篇文章,假设文章是字符串,通常服务端在将文章发布或者存入数据库之前,会对文章内容进行一些处理,比如说敏感词检测、脚本检测等,首先创建文章Msg对象
class Msg { String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } @Override public String toString() { return "Msg{" + "msg='" + msg + '\'' + '}'; } }
- 我们先使用最普通的方式,也就是处理字符串来完成检测
public static void main(String[] args) { Msg m = new Msg(); m.setMsg("大家好:),我是程序狗 devin.com <script> 大家都要996 "); //处理msg String r = m.getMsg(); r = r.replace("<", "["); r = r.replace(">", "]"); r = r.replace("996", "995"); m.setMsg(r); System.out.println(m);
- 如果需要加入更多的检测条件,我们也要每次都replace一下吗?这里我们将创建一个检测接口,也就是Filter
interface Filter { boolean doFilter(Msg m); } //HTML检测器 class HTMLFilter implements Filter { @Override public boolean doFilter(Msg m) { String r = m.getMsg(); r = r.replace("<", "["); r = r.replace(">", "]"); m.setMsg(r); return true; } } //敏感词检测器 class SensitiveFilter implements Filter { @Override public boolean doFilter(Msg m) { String r = m.getMsg(); r = r.replace("996", "995"); m.setMsg(r); return true; } }
- 如何对Msg进行处理,将Filter都加入容器List中,遍历容器即可
List<Filter> filters = new ArrayList<>(); filters.add(new HTMLFilter()); filters.add(new SensitiveFilter()); for(Filter filter:filters ) { filter.doFilter(m); }
当增加新的过滤条件,只需向容器中添加即可
- 可我们的代码,能够像雷军的代码一样优雅吗?
我们定义一个FilterChain来代替容器List
class FilterChain { public List<Filter> filters = new ArrayList<>(); public FilterChain add(Filter filter) { filters.add(filter); return this; } public void remove(Filter filter) { filters.remove(filter); } public boolean doFilter(Msg m) { for(Filter filter:filters ) { if(!filter.doFilter(m)) return false; } return true; } }
- 这样,我们将所有的Filter都添加到FilterChain,可随时增加新的Filter
FilterChain chain = new FilterChain(); chain.add(new HTMLFilter()).add(new SensitiveFilter()); chain.doFilter(m);
class FaceFilter implements Filter { @Override public boolean doFilter(Msg m) { String r = m.getMsg(); r = r.replace(":)", "=_+"); m.setMsg(r); return true; } } class UrlFilter implements Filter { @Override public boolean doFilter(Msg m) { String r = m.getMsg(); r = r.replace("devin.com", "https://wwww.devin.com"); m.setMsg(r); return true; } }
- 此时,新的问题来了,如果我们定义了两条链,如何将它们连接起来?
如果能够连接,程序会更加简洁,也会更加优雅
这里,我们让FilterChain实现Filter接口,那么FilterChain对象就可以当作Filter对象被添加到chain
class FilterChain implements Filter{ } //使用FilterChain链条 FilterChain chain = new FilterChain(); chain.add(new HTMLFilter()).add(new SensitiveFilter()); FilterChain chain1 = new FilterChain(); chain1.add(new FaceFilter()).add(new UrlFilter()); //如何将两条链条连接起来 //让FilterChain本身也是Filter chain.add(chain1); chain.doFilter(m);
至此,责任链模式就讲解完毕了,大家都理解了吗?
小问题
- 为什么Filter和FilterChain中doFilter()都要返回布尔值呢?
-
java责任链模式如何保证其线程安全性?
2015-07-28 15:10:38java责任链模式如何保证其线程安全性?还有一个问题是如何保证多个线程之间的顺序执行? -
责任链模式解析
2019-09-25 19:42:35为什么有责任链模式 传统的软件模式,用户发起请求,需要知道这个请求具体是有谁来处理,如果整个请求处理流程实际多个处理者,那么用户发起请求就需要知道所有的请求者。 这样的缺点就是向用户暴露了太多的内部细节...为什么有责任链模式
传统的软件模式,用户发起请求,需要知道这个请求具体是有谁来处理,如果整个请求处理流程实际多个处理者,那么用户发起请求就需要知道所有的请求者。
这样的缺点就是向用户暴露了太多的内部细节,不安全,而且也造成了系统的复杂性。
责任链模式就是解决这个问题。
责任链的核心就是作为请求者不需要知道请求是由谁来处理的,只需要把请求发给第一个处理者,最终会返回一个处理后的结果。
责任链模式屏蔽了请求的处理过程,发起的请求到底是由谁来处理的,不需要关心。
责任链在实际应用场景
一:比如在用户存钱。
一个存款请求,一个处理者,只能处理人民币。 但是随着业务的发展,请求者的数量增加,处理的类型也增加了,还需要处理美元,欧元,日元等。
这个时候就可以用责任链模式,在第一个处理者后面添加一个链,如果是存人民币,就仍然使用第一个业务逻辑来处理,如果是美元就传递给第二个处理逻辑来处理,如果是日元,欧元,依次传递下去。
这样的好处是,只需要扩展实现类就可以解决需求变更的问题,不需要对原有的业务逻辑做大的更改。
二:用户注册
业务需求:在页面上有用户注册功能:
注册用户分两种: VIP用户和普通用户-
一:VIP用户,已经办理过业务。
VIP用户比普通用户多一个输入项: VIP序列号。注册之后还需要激活。
VIP用户的激活流程也比较特殊:VIP是自动发送到用户的邮箱中,就算激活成功。 -
二:普通用户:注册需要填写一系列信息,不需要VIP序列号。
激活,需要短信验证码。因为这样可以获得用户手机号,这样就可以给用户发送广告短信,哈哈哈。
这个场景就可以使用责任链模式。
从前台传递过来的用户信息,无论是VIP用户,还是普通用户,统一传递到一个接口,通过责任链完成任务的处理。比如定义一个RegisterAction类,把通过HTTP传递过来的对象进行组装,组装成一个HashMap类型的对象UserInfoMap,传递给Handler接口的两个实现类。
具体由哪一个类来处理,根据HashMap上的用户表示来决定。责任链模式的代码示例
分为抽象类,具体实现类,几个属性类,最后场景类:
抽象类
package com.company.ChainOfResponsibiliyPattern; /* 抽象处理者: 然后在需要定义几个具体的实现者,几个实现类 */ public abstract class Handler { private Handler nextHandler; //每个处理者都必须对请求作出处理 public final Response handlerMessage(Request request) { Response response = null; //判断是否是自己的处理级别 if(this.getHandlerLevel().equals(request.getRequestLevel())) { response = this.echo(request); } else {//不属于自己的级别 //判断是否有下一个处理者 if(this.nextHandler != null) { response = this.nextHandler.handlerMessage(request); } else { //如果没有下一个处理者,业务自行处理 } } return response; } //设置下一个处理者是谁 public void setNext(Handler handler2) { this.nextHandler = handler2; } //每个处理者都有一个处理级别 protected abstract Level getHandlerLevel(); //每个处理者都必须实现处理任务 protected abstract Response echo(Request request); }
具体实现类
package com.company.ChainOfResponsibiliyPattern; public class ConcreteHandler1 extends Handler{ //定义自己的处理逻辑 protected Response echo(Request request) { //完成处理逻辑 return null; } //设置自己的处理级别 protected Level getHandlerLevel() { //设置自己的处理级别 return null; } }
package com.company.ChainOfResponsibiliyPattern; public class ConcreteHandler2 extends Handler{ //定义自己的处理逻辑 protected Response echo(Request request) { //完成处理逻辑 return null; } //设置自己的处理级别 protected Level getHandlerLevel() { //设置自己的处理级别 return null; } }
package com.company.ChainOfResponsibiliyPattern; public class ConcreteHandler3 extends Handler{ //定义自己的处理逻辑 protected Response echo(Request request) { //完成处理逻辑 return null; } //设置自己的处理级别 protected Level getHandlerLevel() { //设置自己的处理级别 return null; } }
几个属性类
package com.company.ChainOfResponsibiliyPattern; /* 负责定义请求和处理级别 */ public class Level { //定义一个请求和处理级别 } package com.company.ChainOfResponsibiliyPattern; /* 功能: 负责封装请求 */ public class Request { //请求的等级 public Level getRequestLevel() { return null; } } package com.company.ChainOfResponsibiliyPattern; /* 功能: 负责封装链中返回的结果 */ public class Response { //负责封装链中返回的结果 }
场景类
package com.company.ChainOfResponsibiliyPattern; /* 场景类: 在场景类当中,对链进行组装 */ public class Client { public static void main(String[] args) { //声明所有的处理节点 Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); Handler handler3 = new ConcreteHandler3(); //设置链当中,不同阶段的顺序 1 --》 2 -- 》 3 handler1.setNext(handler2); handler2.setNext(handler3); //提交请求,返回结果 Response response = handler1.handlerMessage(new Request()); } }
参考书籍
《设计模式之禅》 秦小波
-
-
设计模式之责任链模式
2021-01-29 11:56:56Hi,本篇主要是介绍责任链的设计模式原理及场景。 一、设计模式 设计模式是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。它不是语法,而是在特定的场景下提供开发者通用的更简洁的...Hi,本篇主要是介绍责任链的设计模式原理及场景。
一、设计模式
设计模式是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。它不是语法,而是在特定的场景下提供开发者通用的更简洁的实现。1995年共收录23种设计,责任链便是其一,本篇仅介绍该模式的原理、场景、实现思路。
二、责任链是什么?
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
场景:换句话说,我们假设一家互联网x公司有前台接待、市场部、商务部、人事部、技术部、运营部、财务部等等部门,此时前台接待收到一个合同邮件包裹,包裹未注明归属于哪个部门(假设属于技术部)。那么接待需要找到该包裹主人需要一个一个部门去问,于是先去市场部问,市场部:不是我部的;又去商务部问,商务部:不是我部的;又去人事部问,人事部:不是我部的,又去技术部问,技术部:是我部的!前台接待终于找到包裹归属了,万分激动,不用继续跑腿了,可以继续回前台玩手机了。到此处程序也就结束了,也不会往下继续找部门了,否者会一直找 直到明确该包裹是属于某部门或者包裹发错公司了为止。
三、上代码
综上所述,我们开始上代码。
1.前台接待ChainHandler
public class ChainHandler { /** 组织架构 */ private static List<BaseService> handlers = new ArrayList<>(); /** 部门总数 */ private int index = 0; /** * 装载公司组织架构(部门) */ static { BaseService hr = new HRServiceImpl(); BaseService db = new DBServiceImpl(); BaseService md = new MDServiceImpl(); BaseService it = new ITServiceImpl(); BaseService od = new ODServiceImpl(); BaseService fd = new FDServiceImpl(); new ChainHandler().addChainHandler(hr).addChainHandler(db).addChainHandler(md) .addChainHandler(it).addChainHandler(od).addChainHandler(fd); } public ChainHandler addChainHandler(BaseService baseService) { handlers.add(baseService); return this; } public ChainHandler addChainHandlers(List<BaseService> baseServices) { handlers.addAll(baseServices); return this; } /** * 找到包裹归属逻辑 * @param params * @return */ public String next(ChainBo params) { if(index == handlers.size()) { return null; } BaseService baseService = handlers.get(index); index++; String res = baseService.execute(params, this); if(ObjectUtil.isNull(res)) { return "未知包裹"; } return res; } }
2.组织架构BaseService,落实到部门DBServiceImpl、FDServiceImpl、HRServiceImpl、ITServiceImpl、MDServiceImpl、ODServiceImpl
public interface BaseService { String execute(ChainBo params, ChainHandler chainHandler); }
public class DBServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("db".equals(params.getType())) { return "是商务部的"; } return chainHandler.next(params); } }
public class FDServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("fd".equals(params.getType())) { return "是财务部的"; } return chainHandler.next(params); } }
public class HRServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("hr".equals(params.getType())) { return "是人事部的"; } return chainHandler.next(params); } }
public class ITServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("it".equals(params.getType())) { return "是技术部的"; } return chainHandler.next(params); } }
public class MDServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("mkt".equals(params.getType())) { return "是市场部的"; } return chainHandler.next(params); } }
public class ODServiceImpl implements BaseService { @Override public String execute(ChainBo params, ChainHandler chainHandler) { if("od".equals(params.getType())) { return "是运营部的"; } return chainHandler.next(params); } }
public class ChainBo { private String type; public ChainBo() { } public ChainBo(String type) { this.type = type; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
3.测试结果
四、扩展(引入springboot,自动装载bean,接口案例)
未完待续...
-
责任链设计模式讲解
2019-09-26 09:29:03前言很多框架如mybatis,servlet的filter,dubbo,安全框架诸如Spring security、apache shiro都会用到设计模式中的责任链模式,所以学...前言
很多框架如mybatis,servlet的filter,dubbo,安全框架诸如Spring security、apache shiro都会用到设计模式中的责任链模式,所以学习责任链模式成为帮助你学习以上这些框架的一个好的手段之一。今天我们就来了解一下责任链模式。
定义
如果有多个对象(Handler)都有机会处理数据源(RequestSource,这里不是单纯的数据库数据源,可以是一个请求,总之是来源),责任链可以使数据的发送者和接收者解耦,数据沿着责任链传递,直到有一个对象处理了它为止。形成了一条流水线的链条,所以称之为责任链,但是不仅仅局限于链条,还可以成树形或者环形,这取决于你的业务设计。
场景
插件设计、拦截器、过滤器等一些针对切入点的特定链式处理。都可以使用责任链模式。
实现方式
实现方式常用有两种,它们的不同主要是定义处理链的顺序和结构的不同,接下来我们来看看这两种方式。
方式一
通过处理器集合来定义处理顺序。好处在于可以集中管理处理器,指责单一。非常容易理解,容易实现。缺点是如果新增处理器(Handler)势必影响已有的处理器,只能顺序执行。处理流程是这样的:
接下来用代码来实现一下此模式:
HandlerChain 负责维护调用链条的顺序,这里默认实现用List来管理Handler
public interface HandlerChain {
/**
* 调用handler 处理 source.
*
* @param requestSource the request source
*/
void doChain(RequestSource requestSource);
}
// 实现
public class DefaultHandlerChain implements HandlerChain {
// 当前handler指针的位置
private int pos = 0;
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
handlers.add(handler);
}
@Override
public void doChain(RequestSource requestSource) {
int size = handlers.size();
if (pos < size) {
//注意对pos的处理
Handler handler = handlers.get(pos++);
handler.doHandler(requestSource, this);
}
}
}Handler是处理链的节点抽象,是数据源(RequestSource)的具体处理者,它负责对数据的处理以及决定是否进入下一个Handler。
public interface Handler {
/**
* Do handler.
*
* @param requestSource 数据源
* @param handlerChain 传入当前的Chain进行类似递归式的调用。
*/
void doHandler(RequestSource requestSource,HandlerChain handlerChain);
}
// 其中一个实现
public class HeaderHandler implements Handler {
@Override
public void doHandler(RequestSource requestSource, HandlerChain handlerChain) {
// 处理数据
Integer header = requestSource.getHeader();
System.out.println("header handler= " + header);
//继续下一个 你可以根据条件来决定是否继续进行chain
handlerChain.doChain(requestSource);
}
}方式二
该方式利用链表的指针特性。这里利用了链表的一部分特点,通过在当前的Handler指定下一个Handler来作为指针,相比较上面而言,Handler更自治,在节点的处理上更加灵活。
Handler负责指针以及逻辑处理:
public interface Handler {
/**
* 指针指向下一个处理节点.
*
* @return the next
*/
Handler getNext();
/**
* 处理具体逻辑.
*
* @param requestSource the request source
*/
void doHandler(RequestSource requestSource);
}
// 实现
public class HeaderHandler implements Handler {
private Handler next;
public HeaderHandler(Handler next) {
this.next = next;
}
@Override
public Handler getNext() {
return next;
}
@Override
public void doHandler(RequestSource requestSource) {
Integer header = requestSource.getHeader();
System.out.println("header = " + header);
if (next != null) {
next.doHandler(requestSource);
}
}
}总结
责任链模式在各种常见框架中非常常见。所以建议各位在对此设计模式进行认真学习。
demo地址:https://gitee.com/felord/chain-pattern.git
-
小白谈谈责任链模式
2020-03-31 13:53:36责任链就是用于处理相关事务的一条链,链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就依次传递给下一个节点,直到处理完毕。 实现方式: 举例:其中一条车往右行驶,在马路上会... -
设计模式:责任链模式
2019-09-26 08:46:26什么是责任链模式 在一条流水线的链条上分布至多个处理节点(Handler),当...很多框架如 mybatis、servlet 的 filter、dubbo、安全框架诸如 Spring security、apache shiro 都应用到了责任链模式。 实现方式 根据... -
网关服务架构:基于建造者模式/责任链模式实现互联网安全架构
2020-03-04 23:39:24一、理论基础 1.基于网关实现IP黑名单与名单拦截 通过日志可以发现,比如有个客户端恶意请求我们接口,可以通过黑名单和白名单,这时可以把这个IP加入黑名单(或者使用Token+...4.实现API接口安全加密传输(公钥和... -
设计模式之责任链模式讲解
2019-09-24 22:45:15很多框架如mybatis,servlet的filter,dubbo,安全框架诸如Spring security、apache shiro都会用到设计模式中的责任链模式,所以学习责任链模式成为帮助你学习以上这些框架的一个好的手段之一。今天我们就来了解一下... -
java责任链模式及项目实际运用
2017-11-18 21:31:001.前言 上次我们认识了java责任链模式的设计,那么接下来将给大家展示责任链模式项目中的实际运用。...拥有以前的准备的知识点的,我们就可以快速搭建责任链来做安全校验了。 3. 场景模拟 ... -
SPRING与设计模式---责任链模式
2018-02-24 16:17:20spring框架中的应用:spring安全框架security使用责任链模式,框架使用者可以动态地添加删除责任(处理request请求)。UML类图:活动图:源码解析:currentPosition表示责任链的要处理请求链条节点的位置,使用... -
-
每日设计模式——责任链模式
2018-09-29 20:41:43示例说责任链模式 场景:大学生请假。 大学,是一个相对宽松而自由的环境,请假出游都非常的容易,但是为了同学们的安全,学校对学生请假做出了如下规定: 1. 请假时间在3天以内,找班导师签字即可; 2.请假时间... -
餐饮服务安全责任书.doc
2021-01-18 15:37:55餐饮服务安全责任书 “国以民为本,民以食为天,食以安为先”,食品安全问题是人们非常重视的民生问题。餐饮服务位于从“农田到餐桌 这个链条的末端,其重要性就不言而喻,那么大家对餐饮服务安全责任书又有了解吗?小编为... -
利用责任链模式及AOP对日志进行脱敏分享
2018-09-04 16:21:25利用责任链模式及AOP对日志进行脱敏分享 现在公司需要对日志进行脱敏,对一些敏感的值需要掩码处理,已保护用户的数据的安全,对脱敏的字段包括姓名、身份证号码、手机号码、银行账号、邮箱等。 思路如下: 1、... -
java filter过滤器及责任链设计模式
2020-07-07 18:57:04案例一:一个web站点只有用户登录才能继续访问该站点的资源,那么需要用户每次访问都判断是否登陆,若在每个servlet中都写上登陆判断安全控制代码,代码冗余,复用性差,Filter可以很好的解决这个问题。 案例二:一... -
-
【报告分享】2019云安全威胁报告.pdf(附下载链接)
2020-05-26 17:26:31今天给大家分享腾讯安全云鼎实验室和GeekPwn(极棒)联合发布的报告《2019云安全威胁报告.pdf》,报告共包含如下九大部分:1、概述;2、云安全威胁全景;3、云安全责任共担;4、基... -
政府安全资讯精选 2017年第九期 全球互联网企业内容安全责任加重,首批互联网产品隐私条款评审“成绩单”...
2017-09-26 14:50:04摘要: 首批十大互联网产品隐私条款评审“成绩单”公布;全球互联网企业内容安全责任加重;美国证券交易委员会系统遭黑客入侵;欧盟、澳大利亚分别加强跨国网络安全合作 原文链接
-
tb联盟助手 快捷键助手 地址生成 二维码生成器
-
Android 实现view点击水波纹效果
-
SRGAN-PyTorch:超分辨率纸的简单而完整的实现-源码
-
ARKit-CoreLocation:将AR的高精度与GPS数据的规模相结合-源码
-
IAL:逻辑体系结构,Web服务和api REST的实用性-源码
-
2021年 系统架构设计师 系列课
-
3300xl 8mm探头330105-02-12-10-02-05
-
CVE-2021-21972 vCenter 远程命令执行漏洞
-
程序员必修基础套餐课
-
智能停车场云平台(附vue+SpringBoot前后端项目源码)
-
redis-2.6.13.tar.gz
-
spin_mask(加载圈).zip
-
MySQL 高可用(DRBD + heartbeat)
-
Android studio安装和SDK下载安装
-
使用 Linux 平台充当 Router 路由器
-
加载序列帧图片并播放
-
ABAQUS_6.14-5_Win_x64安装
-
【硬核】一线Python程序员实战经验分享(1)
-
牛牛量化策略交易
-
2021-02-26