责任链模式
意图:
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:
在处理消息的时候以过滤很多道。如何解决:拦截的类都实现统一接口。
关键代码:
Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
实现时考虑:
- 实现后继者链
- 定义新的链接(通常在Handler中定义,但也可由ConcreteHandlers来定义)
- 使用已有的链接(比如使用List直接将Handler链接起来)
- 连接后继者
- 表示请求
- 通过硬编码的方式
- 使用处理函数(使用独立的请求对象来封装请求参数)
应用实例:
1、红楼梦中的"击鼓传花"。
2、JS 中的事件冒泡。
3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
优点:
1、降低耦合度。它将请求的发送者和接收者解耦。
2、简化了对象。使得对象不需要知道链的结构。
3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
4、增加新的请求处理类很方便。
缺点:
1、不能保证请求一定被接收。
2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
3、可能不容易观察运行时的特征,有碍于除错。
使用场景:
1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3、可动态指定一组对象处理请求。
类图
【抽象处理者】Handler :
- 定义一个处理请求的接口,抽象方法handleRequest()规范子类处理请求的操作。
- 可以选择实现后继链
【具体处理者】ConcreteHandler : - 处理负责的请求
- 可访问它的后继者
- 如果可处理该请求,就处理;否则将请求转发给它的后继者。
【客户端】Client : - 向链上的具体处理者(ConcreteHandler)对象提交请求。
实例:
例1:
模拟一个村、镇、县的责任链关系请求
抽象处理者
public abstract class Handler {
protected Handler next;
public abstract void handleRequest(String value);
//链接后继者
public Handler next() {
return this.next;
}
//定义新的链接
public void setNext(Handler next) {
this.next = next;
}
}
具体村、镇、县处理者
//村的处理函数
public class VillageHandler extends Handler {
/**
* @see com.pichen.dp.behavioralpattern.chain.Handler#handleRequest()
*/
@Override
public void handleRequest(String value) {
if ("village".equals(value)) {
System.out.println("VillageHandler: handled~");
} else {
System.out.println("VillageHandler: pass~");
this.next.handleRequest(value);
}
}
}
//镇的处理函数
public class TownHandler extends Handler {
@Override
public void handleRequest(String value) {
if ("town".equals(value)) {
System.out.println("VillageHandler: handled~");
} else {
System.out.println("Town: pass~");
this.next.handleRequest(value);
}
}
}
//城的处理函数
public class CountyHandler extends Handler {
@Override
public void handleRequest(String value) {
if ("county".equals(value)) {
System.out.println("County: handled~");
} else if (this.next == null) {
System.out
.println("no next Handler, this request can not be handle~");
} else {
System.out.println("County: pass~");
this.next.handleRequest(value);
}
}
}
测试
public class Client {
public static void main(String[] args) {
Handler villageHandler = new VillageHandler();
Handler townHandler = new TownHandler();
Handler countyHandler = new CountyHandler();
villageHandler.setNext(townHandler);
townHandler.setNext(countyHandler);
System.out.println("test county request:");
villageHandler.handleRequest("county");
System.out.println("\ntest city request:");
villageHandler.handleRequest("city");
}
}
运行结果:
test county request:
VillageHandler: pass~
Town: pass~
County: handled~
test city request:
VillageHandler: pass~
Town: pass~
no next Handler, this request can not be handle~
例2:
我们有一个字符串String msg = “.).,|script|,敏感,被就业,网络授课”;
我们希望应用以下三个规则对字符串进行过滤和谐处理:
(1)将字符串中出现的"<>“符号替换成”[]"
(2)处理字符串中的敏感信息,将被就业和谐成就业
(3)将字符串中出现的"?:“转换成"V”;
字符串会依次运用这三条规则,对字符串进行处理,每个规则都有自己需要完成的责任和任务。
第一步:定义封装请求的类Request和封装处理结果响应的类Response
//封装请求的类Request(请求使用独立对象进行参数化)
public class Request {
String requestStr;
public String getRequest() {
return requestStr;
}
public void setRequest(String request) {
this.requestStr = request;
}
}
//封装响应信息的类Response
public class Response {
String responseStr;
public String getResponse() {
return responseStr;
}
public void setResponse(String response) {
this.responseStr = response;
}
}
第二步:定义具有过滤功能的接口Filter,具体的过滤规则需要实现该接口
/*
* 定义接口Filter,具体的过滤规则需要实现这个接口,最后一个参数添加的意义是我们在Main函数中:
* fc.doFilter(request, response,fc);执行这一步的时候可以按照规则链条一次使用三个过滤规则对字符串进行处理
*/
public interface Filter {
void doFilter(Request request,Response response,FilterChain chain);
}
第三步:定义具体的过滤处理规则
//处理字符串中的HTML标记
public class HTMLFilter implements Filter {
public void doFilter(Request request, Response response,FilterChain chain) {
//将字符串中出现的"<>"符号替换成"[]"
request.requestStr=request.requestStr
.replace('|', '[').replace('|', ']')+
//后面添加的是便于我们观察代码执行步骤的字符串
"----HTMLFilter()";
chain.doFilter(request, response,chain);
response.responseStr+="---HTMLFilter()";
}
}
//定义的过滤敏感字眼的过滤规则
public class SensitiveFilter implements Filter{
public void doFilter(Request request, Response response,FilterChain chain) {
//处理字符串中的敏感信息,将被就业和谐成就业
request.requestStr=request.requestStr
.replace("被就业", "就业").replace("敏感", "")+
//后面添加的是便于我们观察代码执行步骤的字符串
" ---sensitiveFilter()";
chain.doFilter(request, response,chain);
response.responseStr+="---sensitiveFilter()";
}
}
//定义FaceFilter
public class FaceFilter implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
//将字符串中出现的":):"转换成"^V^";
request.requestStr = request.requestStr.replace(".).", "^V^")
//后面添加的是便于我们观察代码执行步骤的字符串
+ "----FaceFilter()";
chain.doFilter(request, response, chain);
response.responseStr += "---FaceFilter()";
}
}
第四步:定义责任链FilterChain
//过滤链条(使用已有的链接)
public class FilterChain implements Filter{
//用List集合来存储过滤规则
List<Filter> filters = new ArrayList<Filter>();
//用于标记规则的引用顺序
int index=0;
//往规则链条中添加规则
public FilterChain addFilter(Filter f) {
filters.add(f);
//代码的设计技巧:Chain链添加过滤规则结束后返回添加后的Chain,方便我们下面doFilter函数的操作
return this;
}
public void doFilter(Request request,Response response,FilterChain chain){
//index初始化为0,filters.size()为3,不会执行return操作
if(index==filters.size()){
return;
}
//每添加一个过滤规则,index自增1,连接后继者
Filter f=filters.get(index);
index++;
//根据索引值获取对应的规律规则对字符串进行处理
f.doFilter(request, response, chain);
}
}
第五步:测试
/*
* 责任链模式:
* 数据消息在进入数据库之前,要被多种过滤规则进行处理,多种规则形成一种链,依次处理
* 给定的数据消息
*/
public class Main {
public static void main(String args[]) {
//设定过滤规则,对msg字符串进行过滤处理
String msg = ":):,<script>,敏感,被就业,网络授课";
//过滤请求
Request request=new Request();
//set方法,将待处理字符串传递进去
request.setRequest(msg);
//处理过程结束,给出的响应
Response response=new Response();
//设置响应信息
response.setResponse("response:");
//FilterChain,过滤规则形成的拦截链条
FilterChain fc=new FilterChain();
//规则链条添加过滤规则,采用的是链式调用
fc.addFilter(new HTMLFilter())
.addFilter(new SensitiveFilter())
.addFilter(new FaceFilter());
//按照FilterChain的规则顺序,依次应用过滤规则
fc.doFilter(request, response,fc);
//打印请求信息
System.out.println(request.getRequest());
//打印响应信息
System.out.println(response.getResponse());
/*
* 处理器对数据进行处理
* --|----|---数据--|-----|---
* 规则1 规则2 规则3 规则4
*/
}
}
运行结果:
V,[script],就业,网络授课----HTMLFilter() —sensitiveFilter()----FaceFilter()
response:—FaceFilter()—sensitiveFilter()—HTMLFilter()