浅析设计模式-责任链模式
什么是责任链模式
什么是责任链,首先来看官方解释:责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
ok,责任链模式的官方解释很明确,可以通俗的理解为将处理者
也就是通常开发中我们见到的过滤器,拦截器,那么如何将这些过滤器连成一条链呢,是的,就是List
代码设计
当我们理解了面向对象,多态,继承这些基础知识后,我们就可以来通过责任链来实现一个小小的问题,首先问题引入:
问题:
学生请假的审批流程:
- 如果学生请假天数小于两天,只需要班主任批准
- 如果学生请假天数大于两天且小于七天,需要系主任批准,批准后回馈给班主任
- 如果学生请假天数大于七天,需要院长批准,且批准后回馈给系主任和班主任
问题分析:这就是一个简单的审批流程,当然,方式很多种,我们怎样通过责任链来实现呢,我们通过一个时序图来看一下这个流程
学生请求发出,到达班主任,班主任判断天数,如果小于两天,直接返回结果,如果大于两天,继续发送请求给系主任,依次类推,这样问题就很明确了,接下俩我们通过代码实现
代码起步
- 我们通过编写POJO类来模拟
Request
和Resoponse
public class Request {
//天数
private int request;
//请求流程
private String process;
public String getProcess() {
return process;
}
public void setProcess(String process) {
this.process = process;
}
public int getRequest() {
return request;
}
public void setRequest(int request) {
this.request = request;
}
@Override
public String toString() {
return "Request{" +
"request='" + request + '\'' +
'}';
}
public class Response {
//返回流程
private String response;
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
@Override
public String toString() {
return "Response{" +
"response='" + response + '\'' +
'}';
}
}
-
通过Filter来实现不同角色的权限
- 定义接口Filter
public interface Filter { Map<String,Object> doFilter(Request request,Response response,ChainFilter chain); }
这里的doFilter为什么会有第三个参数
ChainFilter
稍后解释,这里先记住它
- 通过实现Filter接口来模拟不同的角色权限
到这一步,其实都还好,接下来就是重点了 - 班主任
public class ClassTeacherFilter implements Filter{
@Override
public Map<String,Object> doFilter(Request request, Response response, ChainFilter chain) {
if (request.getRequest() <= 2) {
request.setProcess("递交班主任");
response.setResponse("班主任批准");
} else {
request.setProcess("班主任接受递交给系主任");
chain.doFilter(request,response,chain);
response.setResponse(response.getResponse()+"\n"+"回馈班主任");
}
Map<String, Object> outMap = new HashMap<>();
outMap.put("request", request.getProcess());
outMap.put("response", response.getResponse());
return outMap;
}
}
- 系主任
public class DepartmentHeadFilter implements Filter{
@Override
public Map<String, Object> doFilter(Request request, Response response, ChainFilter chain) {
if (request.getRequest() > 2 && request.getRequest() <=7) {
response.setResponse("系主任批准");
} else {
request.setProcess(request.getProcess() + "\n" + "系主任接受递交给院长");
chain.doFilter(request,response,chain);
response.setResponse(response.getResponse()+"\n"+"回馈系主任");
}
Map<String, Object> outMap = new HashMap<>();
outMap.put("request", request.getProcess());
outMap.put("response", response.getResponse());
return outMap;
}
}
- 院长
public class DeanFilter implements Filter{
@Override
public Map<String, Object> doFilter(Request request, Response response, ChainFilter chain) {
response.setResponse("院长批准");
Map<String, Object> outMap = new HashMap<>();
outMap.put("request", request.getProcess());
outMap.put("response", response.getResponse());
return outMap;
}
}
- 如何将这三个关系组合?也就是刚刚说的List,那么我们通过一个类将这个逻辑封装,命名为ChainFilter
public class ChainFilter {
List<Filter> chainFilter = new ArrayList<Filter>();
int i = 0;
public ChainFilter addFilter(Filter filter) {
this.chainFilter.add(filter);
return this;
}
public Map<String, Object> doFilter(Request request,Response response, ChainFilter chain) {
if(i > 2) return null;
Filter f = chainFilter.get(i);
i++;
Map<String,Object> outMap = f.doFilter(request,response,chain);
return outMap;
}
}
如何理解
其实到这一步的时候,就已经把责任链模式涉及进去了,我来解释一下刚刚的代码,我们反正来看代码,重点来了:
- ChainFilter
问题一:如何将不同的Filter有序的关联起来:
ArrayList,通过addFilter方法实现
问题二:为什么addFilter返回值为自身:
这里目的是为了简化主方法中可以连续调用,请看Main类就可以理解为什么返回自身
问题三:doFilter方法为什么这样写:
这里稍后解释
- 伪代码
班主任
if 班主任可以通过,直接批准
else 递交给系主任
系主任
if 系主任可以批准,直接批准,并返回给班主任
else 递交给院长
院长
直接批准
3.如何实现从班主任到系主任呢,看班主任中的doFilter方法中else中在给response做处理之前有一个chainFilter.doFilter的调用,在ChainFilter类中是不是有一个计数器,当第一次调用班主任后,计数器指向系主任,班主任再去调用chainFilter.doFilter方法时,是不是相当于在调用系主任doFilter方法,这个地方有点绕,其实和递归的思想很像,需要加以理解
没有看懂没关系,我们再来理解一次:这次我还是用伪代码的形式来理解:
班主任:
判断:超出权限
下一步:递交给系主任,也就是通过再次调用chainFilter.doFilter()方法
等待:系主任处理完成后(至于系主任如何处理,班主任不需要知道)等待系主任的回馈,也就是response.setResponse()写在chainFilter.doFilter()方法后面的原因
***********************
当系主任执行结束以后,班主任会接受到系主任的response,这样是不是就可以完成题目中提出的需求,那么加一个院长也是同样的道理
讲到这里我个人觉的代码逻辑包括思路已经明确了,希望大家多提提意见,共同进步
实现效果
public class Main {
public static void main(String[] args) {
Request request = new Request();
request.setRequest(8);
Response response = new Response();
ChainFilter chainFilter = new ChainFilter();
chainFilter.addFilter(new ClassTeacherFilter()).addFilter(new DepartmentHeadFilter())
.addFilter(new DeanFilter());
Map<String,Object> outMap = chainFilter.doFilter(request,response,chainFilter);
System.out.println("请求流程:\n" + outMap.get("request").toString());
System.out.println("返回流程:\n" + outMap.get("response").toString());
}
}