《设计模式》责任链模式
定义:
- 责任链模式将链中每一个节点都看成一个对象,并且将这些节点对象连成一条链,请求会沿着这条链进行传递,直到有对象处理它为止,这使得多个对象都有机会接收请求,避免了请求发送者和接收者之间的耦合。
- 属于行为型设计模式。
责任链模式的角色组成:
- Handler(抽象处理者):定义一个处理请求的抽象方法,并维护一个下一个处理节点对象的引用。
- ConcreteHandler(具体处理者):实现了抽象处理请求方法,并在处理之前进行判断是否有相应的处理权限,有则处理,没有则将请求转发后继者处理。
责任链模式的 UML 类图:
🎈情景案例:大家在公司上班难免遇到有事需要请假的情况,就我所在的公司来说,请假时间不超过3个工作日的,自己的直接领导(leader)可以直接审批,但是如果大于三个工作日不超过五个工作日的,则需要经理(CommonManager)进行审批了,而请假时间超过5个工作日的需要总经理(GeneralManager)进行审批了。其实,请假审批流程这样的场景就可以使用责任链模式模拟,提出的请假请求被一层层传递转发,直到最终的决策者。
抽象处理者 Manager:
public abstract class Manager {
protected String name;
protected Manager superior;
public Manager(String name) {
this.name = name;
}
public void setSuperior(Manager superior) {
this.superior = superior;
}
public abstract void requestAbsence(int days);
}
具体处理者 Leader:
public class Leader extends Manager{
public Leader(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days <= 3) {
System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));
} else {
if (superior != null) {
System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));
superior.requestAbsence(days);
}
}
}
}
具体处理者 CommonManager:
public class CommonManager extends Manager{
public CommonManager(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days > 3 && days <= 5) {
System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));
} else {
if (superior != null) {
System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));
superior.requestAbsence(days);
}
}
}
}
具体处理者 GeneralManager:
public class GeneralManager extends Manager {
public GeneralManager(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days > 5) {
System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));
}
}
}
客户端 Client:
public class Client {
public static void main(String[] args) {
Leader leader = new Leader("主管");
CommonManager commonManager = new CommonManager("经理");
GeneralManager generalManager = new GeneralManager("总经理");
leader.setSuperior(commonManager);
commonManager.setSuperior(generalManager);
leader.requestAbsence(6);
}
}
责任链模式的优点:
- 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,这样的责任链可以简化对象的相互连接,降低耦合度。
- 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
- 易于扩展新的请求处理类(节点),符合开闭原则。
责任链模式的缺点:
- 责任链太长或者处理时间过长,会影响整体性能。
- 如果建链不当,可能会造成循环调用,将导致系统陷入死循环。
- 一个请求也可能因职责链没有被正确配置而得不到处理。
责任链模式的适用场景:
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
- 需要可以动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求,还可以改变链中处理者之间的先后次序。
🎈责任链模式在JDK源码
javax.servlet
包中的应用
Servlet API
中提供了一个 Filter
(过滤器)接口,通过过滤器技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,一般常用于实现 URL
级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Servlet API 中的 Filter
源码如下:
public interface Filter {
// 过滤器第一次初始化时执行,初始化配置参数,在doFilter()方法之前被调用
default void init(FilterConfig filterConfig) throws ServletException {
}
// 在客户端请求及服务器端回复时都将被自动调用,服务器每次在调用web资源之前,都会先调用一下该方法
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
// 结束过滤器,doFilter()方法完成后被调用
default void destroy() {
}
}
Filter
相当于责任链模式中的抽象处理者 Handler
,它是由 doFilter()
方法的最后一个参数 FilterChain
实现一条责任链的,其源码如下:
public interface FilterChain {
/**
* 调用链中的下一个过滤器,如果是调用链中最后一个过滤器,将调用链中最后一个资源
* @param request 将沿着链请求
* @param response 将沿着链回复
*/
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}
FilterChain
类中只定义了一个 doFilter()
方法上,J2EE 只定义了一个规范,具体处理逻辑是由使用者自己来实现,例如 Spring 框架中的实现 MockFilterChain
类:
public class MockFilterChain implements FilterChain {
@Nullable
private ServletRequest request;
@Nullable
private ServletResponse response;
private final List<Filter> filters;
@Nullable
private Iterator<Filter> iterator;
public MockFilterChain() {
this.filters = Collections.emptyList();
}
public MockFilterChain(Servlet servlet) {
this.filters = initFilterList(servlet);
}
public MockFilterChain(Servlet servlet, Filter... filters) {
Assert.notNull(filters, "filters cannot be null");
Assert.noNullElements(filters, "filters cannot contain null values");
this.filters = initFilterList(servlet, filters);
}
private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {
Filter[] allFilters = (Filter[])ObjectUtils.addObjectToArray(filters, new MockFilterChain.ServletFilterProxy(servlet));
return Arrays.asList(allFilters);
}
@Nullable
public ServletRequest getRequest() {
return this.request;
}
@Nullable
public ServletResponse getResponse() {
return this.response;
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(this.request == null, "This FilterChain has already been called!");
if (this.iterator == null) {
this.iterator = this.filters.iterator();
}
if (this.iterator.hasNext()) {
Filter nextFilter = (Filter)this.iterator.next();
nextFilter.doFilter(request, response, this);
}
this.request = request;
this.response = response;
}
public void reset() {
this.request = null;
this.response = null;
this.iterator = null;
}
private static final class ServletFilterProxy implements Filter {
private final Servlet delegateServlet;
private ServletFilterProxy(Servlet servlet) {
Assert.notNull(servlet, "servlet cannot be null");
this.delegateServlet = servlet;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
this.delegateServlet.service(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
public String toString() {
return this.delegateServlet.toString();
}
}
}
MockFilterChain
类把链中的所有 Filter
都放到 List
中,然后在调用 doFilter()
方法时循环迭代List
,也就是说 List
中的 Filter
会按顺序执行。