责任链模式
Chain of Responsibility
责任链模式是将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。
用通俗的话来解释上面的定义:在责任链模式中,多个处理器(也就是定义中说的“对象”)依次处理同一个请求。一个客户端请求先经过处理器A处理,然后再把请求传递给处理器B,处理器B处理完后再传递给处理器C,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理责任,所以叫作责任链模式。
理解思想
Servlet Filter 是一个比较好的模型, 客户端发出请求, 通过过滤器链的层层处理, 到达核心Servlet, Servlet做了核心业务逻辑后得到了响应, 再通过过滤器链的层层处理, 最终回到客户端
需要注意的是, 每个过滤器都可以发挥两次作用, 分别是调用链中下一个过滤器处理的前与后, 前者通常都是只处理Request参数, 后者则通常只处理Response响应
优缺点
- 优点
- 满足开闭原则,提高代码的扩展性, 添加新的规则时, 只需要添加对应的规则类即可, 无需修改原有逻辑
- 更好地处理代码的复杂性, 将大块代码逻辑拆分函数,将大类拆成小类,是应对代码复杂性的常用方法
- 避免请求的送发者和接收者之间的耦合关系, 发送者将请求发送给链而不是指定某一个接收者
- 缺点
- 不能保证每个请求一定被处理, 由于请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能可能受到一定影响
实现方式
常见的责任链实现方式有两种
- 自建链表: 处理器持有下一个处理器的引用, 通常用于有强烈先后顺序关系的责任链中. 举例: 审核流程通常从最底层开始审核, 有权限审核的就操作审核通过或不通过, 没有权限的则交给下一层更高级的权限者审核
- 使用现成的链表, 如 LinkedList: 在链表中加入各个处理器, 依次调用每个处理器的处理方法, 常用于先后关系不敏感的责任链中, 或者需要自行指定添加顺序的责任链中
变种说明
责任链的变种有很多
- 通传式: 链中的每个处理器都要过一遍
- 截断式: 链中的某个处理器处理过后, 则直接返回结果, 不再向后传递
写法说明
责任链的写法不固定
- 入参和出参不一定有, 看情况而定
- 链中的处理器, 有的会将入参和结果都处理一遍, 有的则只处理入参, 有的则只处理结果, 有的则只是打印一些内容, 不对入参和结果做任何处理, 非常灵活
- 有的会把入参和结果都写到处理器的参数中, 这时函数的返回值就是 void, 有的则在处理器的参数中只写入参, 返回值通过函数返回
举例
Servlet Filter 模拟
package com.mrathena.design.pattern.行为型.责任链模式.完整式;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class Test {
// 模拟 Servlet Filter 责任链实现
public static void main(String[] args) {
Map<String, Object> request = new HashMap<>();
Map<String, Object> response = new HashMap<>();
FilterChain chain = new FilterChain(new Servlet());
chain.addFilter(new CheckUsernamePasswordFilter());
chain.addFilter(new CheckTypeFilter());
chain.addFilter(new DesensitizeFilter());
// 准备数据
request.put("username", "username");
request.put("password", "password");
request.put("type", "token");
request.put("type", "phone");
// 传入过滤器链
chain.doFilter(request, response);
// 打印结果
System.out.println(response);
}
}
interface Filter {
void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain);
}
class Servlet {
public void service(Map<String, Object> request, Map<String, Object> response) {
System.out.println("----------");
System.out.println("参数: " + request);
String type = (String) request.get("type");
if ("phone".equals(type)) {
response.put("phone", "18212345678");
}
if ("token".equals(type)) {
response.put("token", UUID.randomUUID().toString().replace("-", ""));
}
System.out.println("结果: " + response);
System.out.println("----------");
}
}
class FilterChain {
public FilterChain(Servlet servlet) {
this.servlet = servlet;
}
private final List<Filter> list = new LinkedList<>();
private final Servlet servlet;
private int index;
public void addFilter(Filter filter) {
for (Filter item : list) {
if (item == filter) {
return;
}
}
list.add(filter);
}
public void doFilter(Map<String, Object> request, Map<String, Object> response) {
if (index < list.size()) {
Filter filter = list.get(index++);
filter.doFilter(request, response, this);
} else {
servlet.service(request, response);
}
}
}
class CheckUsernamePasswordFilter implements Filter {
@Override
public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
String username = (String) request.get("username");
if (null == username) {
response.put("message", "username not exist");
return;
}
String password = (String) request.get("password");
if (null == password) {
response.put("message", "password not exist");
return;
}
if (!("username".equals(username) && "password".equals(password))) {
response.put("message", "username or password is not correct");
return;
}
chain.doFilter(request, response);
}
}
class CheckTypeFilter implements Filter {
@Override
public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
String type = (String) request.get("type");
if (null == type) {
response.put("message", "type not exist");
return;
}
if (!("phone".equals(type) || "token".equals(type))) {
response.put("message", "type value is not correct");
return;
}
chain.doFilter(request, response);
}
}
class DesensitizeFilter implements Filter {
@Override
public void doFilter(Map<String, Object> request, Map<String, Object> response, FilterChain chain) {
chain.doFilter(request, response);
String phone = (String) response.get("phone");
if (null != phone) {
StringBuilder sb = new StringBuilder(phone);
sb.replace(3, 7, "****");
response.put("phone", sb.toString());
}
}
}
通传式 关键字屏蔽
自建链表
package com.mrathena.design.pattern.行为型.责任链模式.通传式.自建链表;
public class Test01 {
// 自建链表
// 举例, 小说的屏蔽字词替换工具
// 八九, 十之八九->十之**
// 体位, 具体位置->具**置
// 西藏, 东躲西藏->东躲**
// 色诱, 景色诱人->景**人
// 国军, 中国军人->中**人
public static void main(String[] args) {
String string = "驻守在西藏的中国军人是伟大的, 在那严酷的自然环境中, 他们将重重困难克服了十之八九, 保证了祖国边疆的安稳";
Handler handler = new Handler01().next(new Handler02().next(new Handler03()));
String result = handler.handle(string);
System.out.println(result);
}
}
abstract class Handler {
private Handler next = null;
public Handler next(Handler handler) {
this.next = handler;
return this;
}
public abstract String replace(String string);
public String handle(String string) {
// 在数据从前向后传递给下一个Handler前可以做一些操作
String result = replace(string);
if (null == this.next) {
return result;
}
// 将当前Handler处理后的数据交给下一个Handler处理
result = next.handle(result);
// 在结果从后向前返回给上一个Handler前也可以做一些操作
return result;
}
}
class Handler01 extends Handler {
@Override
public String replace(String string) {
return string.replace("八九", "**");
}
}
class Handler02 extends Handler {
@Override
public String replace(String string) {
return string.replace("西藏", "**");
}
}
class Handler03 extends Handler {
@Override
public String replace(String string) {
return string.replace("国军", "**");
}
}
使用现成链表
package com.mrathena.design.pattern.行为型.责任链模式.通传式.使用链表;
import java.util.LinkedList;
import java.util.List;
public class Test02 {
// 使用 List
// 举例, 小说的屏蔽字词替换工具
// 八九, 十之八九->十之**
// 体位, 具体位置->具**置
// 西藏, 东躲西藏->东躲**
// 色诱, 景色诱人->景**人
// 国军, 中国军人->中**人
public static void main(String[] args) {
String string = "驻守在西藏的中国军人是伟大的, 在那严酷的自然环境中, 他们将重重困难克服了十之八九, 保证了祖国边疆的安稳";
HandlerChain chain = new HandlerChain();
chain.add(new Handler01());
chain.add(new Handler02());
chain.add(new Handler03());
String result = chain.handle(string);
System.out.println(result);
}
}
interface Handler {
String handle(String string);
}
class Handler01 implements Handler {
@Override
public String handle(String string) {
return string.replace("八九", "**");
}
}
class Handler02 implements Handler {
@Override
public String handle(String string) {
return string.replace("西藏", "**");
}
}
class Handler03 implements Handler {
@Override
public String handle(String string) {
return string.replace("国军", "**");
}
}
class HandlerChain {
private final List<Handler> list = new LinkedList<>();
public void add(Handler handler) {
list.add(handler);
}
public String handle(String string) {
String result = string;
for (Handler handler : list) {
result = handler.handle(result);
}
return result;
}
}
截断式 请假审批流程
package com.mrathena.design.pattern.行为型.责任链模式.截断式;
public class Test {
public static void main(String[] args) {
int days = 31;
Reviewer reviewer = new Leader().next(new Manager().next(new Boss()));
reviewer.review(days);
}
}
abstract class Reviewer {
protected Reviewer next = null;
public Reviewer next(Reviewer reviewer) {
this.next = reviewer;
return this;
}
public abstract void review(int days);
}
class Leader extends Reviewer {
@Override
public void review(int days) {
if (days <= 3) {
System.out.println("Leader review pass");
return;
}
next.review(days);
}
}
class Manager extends Reviewer {
@Override
public void review(int days) {
if (days <= 7) {
System.out.println("Manager review pass");
return;
}
next.review(days);
}
}
class Boss extends Reviewer {
@Override
public void review(int days) {
if (days <= 30) {
System.out.println("Boss review pass");
} else {
System.out.println("Boss review not pass");
}
}
}