责任链模式
本文从以下几个示例介绍责任链模型
一、概念
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
二、示例展示
1、简单示例引入
(1)示例介绍:模拟客户端向服务端发送消息时校验问题,比如说我们发送给服务端的消息要进行敏感词,脚本信息的过滤等处理,特殊情况处理之后将消息发送给服务器。
(2)代码示例
package net.oschina.design.chainofresponsibility.example;
/**
* 一个简单的例子引出责任链模式 消息处理类
*
* @author Freedom
*
*/
public class MsgProcess {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
/**
* 消息处理程序 客户端-->到服务端的消息进行一个过滤 过滤敏感字符,过滤脚本等信息
*
* @param msg
* @return
*/
public String doFilter() {
// 最简单 的做饭直接在该方法中进行处理
// 1. 处理脚本 <> --> []
String r = msg;
r = r.replace("<", "[").replace(">", "]");
// 处理敏感字符
r = r.replace("潜规则", "***").replace("SB", "***");
// 引发思考,如果说程序中又多了很多种对字符串过滤规则,则每次都要修改这个类中的方法不便于扩展
// 想法:找出需求中的变化部分,因为过滤规则可以有多重,因此将过滤规则抽象为接口,加其实现这样就方法便扩展了
return r;
}
}
package net.oschina.design.chainofresponsibility.example;
/**
* 测试方法
*
* @author Freedom
*
*/
public class Main {
public static void main(String[] args) {
String msg = "xxx被潜规则<script>,真的很SB,且行且珍惜";
MsgProcess mp = new MsgProcess();
mp.setMsg(msg);
System.out.println(mp.doFilter());
}
}
①示例引发的思考
通过上述示例可以看出,如果说,对客户端发送的消息过滤的规则修改了或者是新增了一些过滤规则,每次 都要修改该类中方法,明显违背了开发关闭原则;
②解决方案
通过上述示例,明确得出变化的部分是消息的校验规则不同,因此可以将消息的校验规则抽象出一个接口,然后子类实现该接口形成一个行为族,看如下示例。
2、过滤规则抽象为接口及子类实现的方式
2.1、代码示例
2.1.1 过滤规则的接口
package net.oschina.design.chainofresponsibility.simplefilter.filterinterface;
/**
* 处理客户端消息的过滤器接口 后续如果有多重过滤规则,只需要实现该接口,重写方法即可
*
* @author Freedom
*
*/
public interface Filter {
/**
* 过滤消息
*
* @param msg
* @return
*/
String doFilter(String msg);
}
2.1.2 过滤规则的实现类
package net.oschina.design.chainofresponsibility.simplefilter.filterinterface.impl;
import net.oschina.design.chainofresponsibility.simplefilter.filterinterface.Filter;
/**
* 处理脚本的过滤器
*
* @author Freedom
*
*/
public class ScriptFilter implements Filter {
@Override
public String doFilter(String msg) {
String r = msg;
r = r.replace("<", "[").replace(">", "]");
return r;
}
}
package net.oschina.design.chainofresponsibility.simplefilter.filterinterface.impl;
import net.oschina.design.chainofresponsibility.simplefilter.filterinterface.Filter;
/**
* 处理敏感词的过滤器
*
* @author Freedom
*
*/
public class SensitiveFilter implements Filter {
@Override
public String doFilter(String msg) {
String r = msg;
r = r.replace("潜规则", "***").replace("SB", "***");
return r;
}
}
2.1.3 消息处理程序类
package net.oschina.design.chainofresponsibility.simplefilter;
import net.oschina.design.chainofresponsibility.simplefilter.filterinterface.Filter;
import net.oschina.design.chainofresponsibility.simplefilter.filterinterface.impl.ScriptFilter;
import net.oschina.design.chainofresponsibility.simplefilter.filterinterface.impl.SensitiveFilter;
/**
* 一个简单的例子引出责任链模式 消息处理类
*
* @author Freedom
*
*/
public class MsgProcess {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 获取过滤器并保存
// 如果后续有新增加的过滤器,只需要在数据里面添加即可
// 此方式可以改变过滤顺序,只需改变数据中元素存放位置即可
Filter[] filters = { new ScriptFilter(), new SensitiveFilter() };
/**
* 消息处理程序 客户端-->到服务端的消息进行一个过滤 过滤敏感字符,过滤脚本等信息 思考:
* 上述方式只是一条过滤规则,如果我们添加了一条过滤规则,并且该规则中有多个简单的过滤规则,如何实现?
*
* @param msg
* @return
*/
public String processMsg() {
String r = msg;
for (Filter f : filters) {
r = f.doFilter(r);
}
return r;
}
}
该类的实现中 processMsg()方法,只需要之前的实现的过滤规则的子类作为一个集合对象组合到该类中即可。遍历集合中过滤规则子类然后调用各自的过滤方法。
2.2 、示例思考
(1)上述示例可以看出,如果程序中需要新增过滤规则,只需要实现Filter接口即可。但是,方法中只是展示了一条过滤规则链,如果说有程序中又新增了一条过滤规则链而且该过滤规则链中同样也是有多了个过滤规则对象组成,又该如何实现?
(2)分析上述变化:其实解决思路可以将新增的过滤规则链看成一个整体,该整体的无外乎也是对消息的过滤,因此新增的过滤规则链(整体对象)其实也是一个Filter对象。请看如下示例。
3、程序中有多条过滤规则链的实现
3.1、代码示例
3.1.1、过滤规则接口及其实现类
package net.oschina.design.chainofresponsibility.manyfilter.filterinterface;
/**
* 处理客户端消息的过滤器接口 后续如果有多重过滤规则,只需要实现该接口,重写方法即可
*
* @author Freedom
*
*/
public interface Filter {
/**
* 过滤消息
*
* @param msg
* @return
*/
String doFilter(String msg);
}
package net.oschina.design.chainofresponsibility.manyfilter.filterinterface.impl;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.Filter;
/**
* 处理脚本的过滤器
*
* @author Freedom
*
*/
public class ScriptFilter implements Filter {
@Override
public String doFilter(String msg) {
String r = msg;
r = r.replace("<", "[").replace(">", "]");
return r;
}
}
package net.oschina.design.chainofresponsibility.manyfilter.filterinterface.impl;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.Filter;
/**
* 处理敏感词的过滤器
*
* @author Freedom
*
*/
public class SensitiveFilter implements Filter {
@Override
public String doFilter(String msg) {
String r = msg;
r = r.replace("潜规则", "***").replace("SB", "***");
return r;
}
}
3.1.2、新增过滤规则链的实现类
package net.oschina.design.chainofresponsibility.manyfilter;
import java.util.ArrayList;
import java.util.List;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.Filter;
/**
* 过滤器链 目的:处理当多了一条链式规则时(该过滤链中有多条简单过滤规则)方式 想法:将该过滤链看成一个整体,其实质也就是一个过滤规则
* 为了将该过滤规则链加入其他过滤规则链中,因此该类要实现Filter接口 简单讲:就是将多个过滤器对象组成的过滤规则链看成一个整体,该整体也是一个过滤规则
*
* @author Freedom
*
*/
public class FilterChain implements Filter {
// 保存过滤器对象的链表
private List<Filter> filters = null;
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
public FilterChain() {
filters = new ArrayList<Filter>();
}
// 添加过滤器对象
// 该方法返回对象本身的目的是为了,能够链式的调用方法 ,如:this.addFilter(f).addFilter(f)...
public Filter addFilter(Filter f) {
if (!filters.contains(f)) {
filters.add(f);
}
return this;
}
@Override
public String doFilter(String msg) {
String r = msg;
for (Filter f : filters) {
r = f.doFilter(r);
}
return r;
}
}
3.1.3、处理消息的程序类
package net.oschina.design.chainofresponsibility.manyfilter;
import java.util.List;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.Filter;
/**
* 一个简单的例子引出责任链模式 消息处理类
*
* @author Freedom
*
*/
public class MsgProcess {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 过滤规则链
// 简单期间就不用链表结构了
private FilterChain chain;
public FilterChain getChain() {
return chain;
}
public void setChain(FilterChain chain) {
this.chain = chain;
}
public MsgProcess(FilterChain chain) {
this.chain = chain;
}
/**
* 消息处理程序 客户端-->到服务端的消息进行一个过滤 过滤敏感字符,过滤脚本等信息 思考:
* 上述方式只是一条过滤规则,如果我们添加了一条过滤规则,并且该规则中有多个简单的过滤规则,如何实现?
*
* @param msg
* @return
*/
public String processMsg() {
String r = msg;
// 获取过滤规则链中过滤规则对象
List<Filter> filters = chain.getFilters();
for (Filter f : filters) {
r = f.doFilter(r);
}
return r;
}
}
主函数:
package net.oschina.design.chainofresponsibility.manyfilter;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.impl.ScriptFilter;
import net.oschina.design.chainofresponsibility.manyfilter.filterinterface.impl.SensitiveFilter;
/**
* 测试方法 思考:目前的情况只是针对客户端到服务端消息的过滤
* 如果说服务端到客户端的消息同样也要实现过滤,并且客户端到服务端过滤规则结束时,服务端到客户端校验规则开始(校验规则倒序)要如何实现?
*
* @author Freedom
*
*/
public class Main {
public static void main(String[] args) {
String msg = "xxx被潜规则<script>,真的很SB,且行且珍惜";
// 第一条过滤规则链
FilterChain chain = new FilterChain();
chain.addFilter(new ScriptFilter());
chain.addFilter(new SensitiveFilter());
// 第二条过滤规则链
FilterChain chain1 = new FilterChain();
chain1.addFilter(new ScriptFilter());
// 将第二条过滤规则链添加到第一条过滤规则链中
chain.addFilter(chain1);
MsgProcess mp = new MsgProcess(chain);
mp.setMsg(msg);
System.out.println(mp.processMsg());
}
}
3.2、对示例的思考
(1)之前的示例展示的都是对客户端发送消息到服务端的处理。同样服务端响应消息到客户端同样也要进行处理并且处理的过滤规则顺序与之前客户端到服务端的处理规则顺序相反,又该如何实现呢?
(2)问题分析:无论是客户端发消息到服务端,还是服务端响应消息到客户端,其实质都是对消息的过滤,这时我们只需要将两者发送的消息封装到对象中,然后对各自对象中消息进行处理。关于过滤规则逆序处理方式,我们只需将过滤规则链对象出入接口方法中,在方法的实现上加上计数器,每当请求消息处理完成后不立即处理相同过滤规则的响应消息,而是处理下一种过滤规则的请求消息,依次类推。请看如下示例。
4、同时处理请求以及响应消息的过滤
4.1、代码示例
4.1.1、过滤接口以及其实现类
package net.oschina.design.chainofresponsibility.finalfilter;
/**
*
* 处理客户端到服务端的消息的过滤,同时也处理服务端到客户端消息的过滤
*
* 为了实现 服务端 到客户端消息处理时,过滤规则倒序的情况要将FilterChain对象传入到方法中
*
* @author Freedom
*
*/
public interface Filter {
/**
* 过滤消息 该情况不能实现服务端到客户端消息过滤时,过滤规则的倒序
*
* @param msg
* @return
*/
// void doFilter(Request req, Response resp);
/**
* 要将FilterChain传入方法中实现服务端--》客户端过滤规则倒序
*/
void doFilter(Request req, Response resp, FilterChain chain);
}
package net.oschina.design.chainofresponsibility.finalfilter;
/**
* 处理脚本的过滤器
*
* @author Freedom
*
*/
public class ScriptFilter implements Filter {
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
// 处理请求消息的过滤
String reqMsg = req.reqMsg;
reqMsg = reqMsg.replace("<", "[").replace(">", "]")
+ "----scriptFilter";
System.out.println(reqMsg);
// 处理服务器端响应消息之前先处理所有客户端消息的过滤
chain.doFilter(req, resp, chain);
// 处理响应消息的过滤
String respMsg = resp.respMsg;
System.out.println(respMsg + " --response scriptFilter");
}
// @Override
// public void doFilter(Request req, Response resp) {
// // 处理请求消息的过滤
// String reqMsg = req.reqMsg;
// reqMsg = reqMsg.replace("<", "[").replace(">", "]")
// + "----scriptFilter";
// System.out.println(reqMsg);
//
// // 处理响应消息的过滤
// String respMsg = resp.respMsg;
// System.out.println(respMsg + " --response scriptFilter");
// }
}
package net.oschina.design.chainofresponsibility.finalfilter;
/**
* 处理敏感词的过滤器
*
* @author Freedom
*
*/
public class SensitiveFilter implements Filter {
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
String reqMsg = req.reqMsg;
reqMsg = reqMsg.replace("潜规则", "***").replace("SB", "***")
+ "----SensitiveFilter";
System.out.println(reqMsg);
chain.doFilter(req, resp, chain);
// 处理响应消息的过滤
String respMsg = resp.respMsg;
System.out.println(respMsg + " --response SensitiveFilter");
}
// @Override
// public void doFilter(Request req, Response resp) {
// // 处理请求消息的过滤
// String reqMsg = req.reqMsg;
// reqMsg = reqMsg.replace("潜规则", "***").replace("SB", "***")
// + "----SensitiveFilter";
// System.out.println(reqMsg);
//
// // 处理响应消息的过滤
// String respMsg = resp.respMsg;
// System.out.println(respMsg + " --response SensitiveFilter");
//
// }
}
4.1.2、过滤规则链类
package net.oschina.design.chainofresponsibility.finalfilter;
import java.util.ArrayList;
import java.util.List;
/**
* 过滤器链 目的:处理当多了一条链式规则时(该过滤链中有多条简单过滤规则)方式 想法:将该过滤链看成一个整体,其实质也就是一个过滤规则
* 为了将该过滤规则链加入其他过滤规则链中,因此该类要实现Filter接口 简单讲:就是将多个过滤器对象组成的过滤规则链看成一个整体,该整体也是一个过滤规则
*
* @author Freedom
*
*/
public class FilterChain implements Filter {
// 保存过滤器对象的链表
private List<Filter> filters = null;
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
public FilterChain() {
filters = new ArrayList<Filter>();
}
// 添加过滤器对象
// 该方法返回对象本身的目的是为了,能够链式的调用方法 ,如:this.addFilter(f).addFilter(f)...
public Filter addFilter(Filter f) {
if (!filters.contains(f)) {
filters.add(f);
}
return this;
}
// @Override
// public void doFilter(Request req, Response resp) {
// for (Filter f : filters) {
// f.doFilter(req, resp);
// }
// }
// 计算器
int count = 0;
@Override
public void doFilter(Request req, Response resp, FilterChain chain) {
if (count == filters.size()) {
return;
}
Filter filter = filters.get(count);
count++;
filter.doFilter(req, resp, chain);
}
}
4.1.3、请求消息实体及响应消息实体
package net.oschina.design.chainofresponsibility.finalfilter;
/**
* 客户端到服务端发送消息的对象
*
* @author Freedom
*
*/
public class Request {
// 简单期间,只定义该属性
public String reqMsg;
public String getReqMsg() {
return reqMsg;
}
public void setReqMsg(String reqMsg) {
this.reqMsg = reqMsg;
}
}
package net.oschina.design.chainofresponsibility.finalfilter;
/**
* 响应对象,服务端向客户端发消息的对象
*
* @author Freedom
*
*/
public class Response {
public String respMsg;
public String getRespMsg() {
return respMsg;
}
public void setRespMsg(String respMsg) {
this.respMsg = respMsg;
}
}
4.1.4、主函数
package net.oschina.design.chainofresponsibility.finalfilter;
public class Main {
public static void main(String[] args) {
Request req = new Request();
req.setReqMsg("xxx被潜规则<script>,真的很SB,且行且珍惜");
FilterChain chain = new FilterChain();
chain.addFilter(new ScriptFilter());
chain.addFilter(new SensitiveFilter());
chain.doFilter(req, new Response(), chain);
}
}
运行结果:
4.2、程序运行分析
(1)Debug模式:
(2)序列图