责任链设计模式

责任链设计模式


1. 简单介绍

责任链模式(Chain of Responsibility)是一种行为型设计模式。该模式使得多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链(与链表结构类似),并沿着这条链传递该请求,直到有一个对象完成处理为止。

2. 使用场景
  • 需要动态指定一组对象完成请求的处理
  • 一个请求可以由多个对象进行处理,具体交由哪个对象处理由程序运行时自动确定
  • 处理流(即处理链)需要动态的扩展
3. 场景举例

Servlet中,过滤器的过滤流在设计上采用了责任链模式。 用户可以根据自身的需求,对过滤器链(FilterChain) 进行扩展,并定义过滤器的过滤顺序。当HTTP请求进入过滤器链后,该请求会按过滤器链的顺序对请求进行逐项过滤。对于不满足过滤条件的请求,则直接返回,不会对请求做具体的处理。

4. UML类图

责任链模式UML类图

5. 具体实现

描述

  • 背景:土豆经过处理链(责任链)后变成美味的薯片
  • CleanHandler:处理链中的一换,作用是清洗土豆
  • SliceHandler:处理链中的一换,作用是对土豆进行切片
  • CookHandler:处理链中的一换,作用是对土豆进行烹饪
  • Client:客户端,负责去菜场买土豆

代码实现

Handler.java

/**
 * 处理类顶层接口
 */  
public interface Handler {

    /**
     * 设置后置处理类
     */
    Handler setNextHandler(Handler handler);

    /**
     * 处理方法
     */
    void handle(Potato potato);
}

CleanHandler.java

/**
 * 清洗土豆处理类
 */
public class CleanHandler implements Handler {

    private Handler nextHandler;

    @Override
    public Handler setNextHandler(Handler handler) {
        this.nextHandler = handler;
        return this;
    }

    @Override
    public void handle(Potato potato) {
        // 清洗土豆
        System.out.println("清理土豆");
        // 土豆变得干净
        potato.clean = true;

        if (nextHandler != null) {
            nextHandler.handle(potato);
        }
    }
}

SliceHandler.java

/**
 * 对土豆进行切片
 */
public class SliceHandler implements Handler {
    private Handler nextHandler;

    @Override
    public Handler setNextHandler(Handler handler) {
        this.nextHandler = handler;
        return this;
    }

    @Override
    public void handle(Potato potato) {
        // 对土豆切片
        System.out.println("土豆切片");
        // 土豆形状变成片
        potato.shape = "slice";

        if (nextHandler != null) {
            nextHandler.handle(potato);
        }
    }
}

CookHandler.java

/**
 * 对土豆进行烹饪
 */
public class CookHandler implements Handler {

    private Handler nextHandler;

    @Override
    public Handler setNextHandler(Handler handler) {
        this.nextHandler = handler;
        return this;
    }

    @Override
    public void handle(Potato potato) {
        // 油炸土豆片
        System.out.println("油炸土豆片");
        // 撒上番茄粉
        System.out.println("撒上番茄粉");
        // 土豆变得干净
        potato.taste = "番茄味,嘎嘣脆";

        if (nextHandler != null) {
            nextHandler.handle(potato);
        }
    }
}

Potato.java

/**
 * 土豆
 */
public class Potato {

    /**
     * 初始时的土豆是脏的
     */
    protected boolean clean = false;

    /**
     * 初始时的土豆是圆的
     */
    protected String shape = "round";

    /**
     * 初始时的土豆是没有味道的
     */
    protected String taste = "无味的";

    @Override
    public String toString() {
        return "Potato{" +
                "clean=" + clean +
                ", shape='" + shape + '\'' +
                ", taste='" + taste + '\'' +
                '}';
    }
}

Client.java

/**
 * 客户端
 */  
public class Client {

    public static void main(String[] args) {
        Handler cleanHandler = new CleanHandler();
        Handler sliceHandler = new SliceHandler();
        Handler cookHandler = new CookHandler();

        // 土豆清洗完后,进行切片
        cleanHandler.setNextHandler(sliceHandler);
        // 土豆切片后,进行油炸调味
        sliceHandler.setNextHandler(cookHandler);

        // 从菜场买来一个为处理的土豆
        Potato potato = new Potato();
        // 查看土豆状态
        // 输出:Potato{clean=false, shape='round', taste='无味的'}
        System.out.println(potato.toString());

        // 把土豆交给责任链处理
        cleanHandler.handle(potato);
        // 查看处理完成后的土豆状态
        // 输出:Potato{clean=true, shape='slice', taste='番茄味,嘎嘣脆'}
        System.out.println(potato.toString());
    }
}
7. 源码展示

SpringMVC中的拦截器(Interceptor) 在对请求进行拦截过滤时,采用了责任链设计模式。使用SrpingMVC框架时,用户可以根据自身需求定义多个拦截器。这些拦截器的引用都被HandlerExecutionChain中的成员数组变量*HandlerInterceptor[ ]所持有。当浏览器发起请求到达前端控制器DispatcherServlet时,由DispatcherServlet将请求交给HandlerExecutionChain进行拦截处理。与Gof提出的责任链模式不同的是,拦截器不再持有后置(即下一个)拦截器的引用,而是通过HandlerInterceptor[ ]*索引找出下一个拦截器。其中源码如下:

DispatcherServlet.java

public class DispatcherServlet extends FrameworkServlet {

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        // 持有所有拦截器的引用
        HandlerExecutionChain mappedHandler = null;

        try {
                    
            // 部分代码省略,只展示核心代码
                    
            // applyPreHandle方法,将请求进行前置拦截处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 请求的具体执行
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            if (asyncManager.isConcurrentHandlingStarted()) {
                 return;
            }

            // applyPostHandle方法,将请求进行后置拦截处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } 
                
            // 部分代码省略,只展示核心代码
        } 
    }
}

HandlerExecutionChain.java

public class HandlerExecutionChain {
    
    private HandlerInterceptor[] interceptors;
    
    // 注入拦截器
    public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
        this.interceptorIndex = -1;
        if (handler instanceof HandlerExecutionChain) {
            HandlerExecutionChain originalChain = (HandlerExecutionChain)handler;
            this.handler = originalChain.getHandler();
            this.interceptorList = new ArrayList();
            CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
            CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
        } else {
            this.handler = handler;
            this.interceptors = interceptors;
        }
    } 
    
    // 拦截器链对请求进行前置拦截处理
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            // 遍历所有拦截器
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                // 具体的拦截器对请求进行预处理
                if (!interceptor.preHandle(request, response, this.handler)) {
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }

        return true;
    } 
    
    // 拦截器链对请求进行后置拦截处理
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            // 遍历所有拦截器
            for(int i = interceptors.length - 1; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];
                // 具体的拦截器对响应进行后置处理
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值