设计模式 — 责任链模式
1.1 简介
- 责任链模式为请求创建一个接收者对象链,每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把请求传给下一个接收者,依此类推
- 责任链模式避免了请求的发送者和接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
1.2 责任链模式优缺点
优点
降低耦合度。它将请求的发送者和接收者解耦
简化了对象,使得对象不需要知道链的结构
增强给对象指派职责的灵活性,允许动态地新增或者删除责任链
增加新的请求处理类方便
缺点
不能保证请求一定被接收;
系统性能将受到一定影响,调试时不方便,可能会造成循环调用
2 模式结构
2.1 对象定义
Handler(抽象处理者) : 定义一个处理请求的接口,提供对后续处理者的引用
ConcreteHandler(具体处理者) : 抽象处理者的子类,处理用户请求,可选将请求处理掉还是传给下家;在具体处理者中可以访问链中下一个对象,以便请求的转发
2.2 类图及设计
代码详解:
抽象处理者
public abstract class Handler { protected Handler nextHandler; // 下一个责任链成员 public Handler getNextHandler() { return nextHandler; } public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; } // 处理传递过来的时间 public abstract void handleMessage(int type); }
具体处理者
在当前处理者对象无法处理时,将执行权传给下一个处理者对象
public class ConcreteHandler1 extends Handler { @Override public void handleMessage(int type) { if (type == 1 || type == 3) { System.out.println("ConcreteHandler1解决了问题!"); } else { System.out.println("ConcreteHandler1解决不了问题......"); if (nextHandler != null) { nextHandler.handleMessage(type); } else { System.out.println("没有人能处理这个消息"); } } } } public class ConcreteHandler2 extends Handler { @Override public void handleMessage(int type) { if (type == 2 || type == 5) { System.out.println("ConcreteHandler2解决了问题!"); } else { System.out.println("ConcreteHandler2解决不了问题......"); if (nextHandler != null) { nextHandler.handleMessage(type); } else { System.out.println("没有人能处理这个消息"); } } } } public class ConcreteHandler3 extends Handler { @Override public void handleMessage(int type) { if (type == 4 || type == 6) { System.out.println("ConcreteHandler3解决了问题!"); } else { System.out.println("ConcreteHandler3解决不了问题......"); if (nextHandler != null) { nextHandler.handleMessage(type); } else { System.out.println("没有人能处理这个消息"); } } } }
Client 客户端调用
// 初始化责任链:handler1 -> handler2 -> handler3 Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); Handler handler3 = new ConcreteHandler3(); handler2.setNextHandler(handler3); handler1.setNextHandler(handler2); // 处理事件 System.out.println("--------------Message1"); handler1.handleMessage(1); System.out.println("--------------Message2"); handler1.handleMessage(2); System.out.println("--------------Message3"); handler1.handleMessage(4); System.out.println("--------------Message4"); handler1.handleMessage(7);
从上述模式可以知道,当我们需要多个 ifelse
做逻辑判断的时候,可以引入,从而提高代码可维护性
2.3 适用场景:
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
- 在不明确指定接收者的情况下,向多个对象中的某一个对象提交一个请求
- 可动态指定一组对象的处理请求
更详细分析请看这篇:实际项目中运用责任链模式
另一个例子阐述:直接用马士兵老师中的一个例子来讲解
我们有一个字符串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); }
第三步:定义具体的过滤处理规则
规则一
package com.bjsxt.dp.filter; //处理字符串中的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()"; } }
规则二
package com.bjsxt.dp.filter; //定义的过滤敏感字眼的过滤规则 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()"; } }
规则三
package com.bjsxt.dp.filter; //定义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
package com.bjsxt.dp.filter; import java.util.ArrayList; import java.util.List; //过滤链条 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); } }
第五步:测试一下我们的代码
package com.bjsxt.dp.filter; /* * 责任链模式: * 数据消息在进入数据库之前,要被多种过滤规则进行处理,多种规则形成一种链,依次处理 * 给定的数据消息 */ 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()