责任链模式浅析

  • 2019 年 10 月 4 日
  • 筆記

在开始本文之前,我们先来看下生活中的的一些场景:

  • 场景1:请假

某天你想请个假,比如1到3天,直接主管可以审批;3天以上需要部门主管审批;15天以上需要副总裁审批 … …

  • 场景2:打折

某天你去买个车,和销售人员讨论折扣的问题。这个时候,可能95折以上销售能拍板;85折需要销售经理拍板;75折需要区域经理拍板 … …

这些场景,当某一个人或者节点不能处理的时候,需要抛给下一个节点处理。这就是我们今天要聊的责任链模式可以做的事情。

一、责任链模式的基本介绍

1.1 意图

责任链的意图是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之前的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

1.2 结构

责任链模式的基本结构如下:

  • Handler
    • 定义一个处理请求的接口。
  • ConcreteHandler
    • 处理它所负责的请求
    • 可访问它的后继者

二、责任链模式示例

本责任链模式示例模拟买东西打折扣,销售人员能处理9折以上的折扣;如果折扣低于9折向销售经理请示;同理,销售经理能处理8折以上的折扣,如果折扣低于8折,其需要向区域经理请示;区域经理能处理7折以上的折扣。

  • DiscountHandler (Handler)

折扣处理类,其包含一个折扣处理方法handle, 还有一个后继处理者 successor。

package com.wangmengjun.tutorial.designpattern.responsibility;    public abstract class DiscountHandler {      private DiscountHandler successor;      public abstract void handle(double discount);      /**     * @return the successor     */    public DiscountHandler getSuccessor() {      return successor;    }      /**     * @param successor the successor to set     */    public void setSuccessor(DiscountHandler successor) {      this.successor = successor;    }    }  
  • 3个ConcreteHandler

定义三个具体的处理者类,分别对应销售人员、销售经理以及区域经理的处理,代码如下:

package com.wangmengjun.tutorial.designpattern.responsibility;    public class SalemanDiscountHandler extends DiscountHandler {      @Override    public void handle(double discount) {      if(discount > 0.9) {        System.out.println("Saleman Discount ==>  " + discount);      }else {        this.getSuccessor().handle(discount);      }      }    }  
package com.wangmengjun.tutorial.designpattern.responsibility;    public class SaleManagerDiscountHandler extends DiscountHandler {      @Override    public void handle(double discount) {      if(discount > 0.8) {        System.out.println("SaleManager Discount ==>  " + discount);      }else {        this.getSuccessor().handle(discount);      }      }    }  
  package com.wangmengjun.tutorial.designpattern.responsibility;    public class AreaManagerDiscountHandler extends DiscountHandler {        @Override      public void handle(double discount) {        if(discount > 0.7) {          System.out.println("AreaManager Discount ==>  " + discount);        }else {          System.out.println("折扣太低,真不能賣了~~");        }        }    }

模拟不同的折扣测试一下

package com.wangmengjun.tutorial.designpattern.responsibility;    public class ChainMain {      public static void main(String[] args) {        DiscountHandler salemanHandler = new SalemanDiscountHandler();      DiscountHandler saleManagerHandler = new SaleManagerDiscountHandler();      DiscountHandler areaManagerHandler = new AreaManagerDiscountHandler();        salemanHandler.setSuccessor(saleManagerHandler);      saleManagerHandler.setSuccessor(areaManagerHandler);        double discount = 0.95;      salemanHandler.handle(discount);        discount = 0.88;      salemanHandler.handle(discount);        discount = 0.75;      salemanHandler.handle(discount);          discount = 0.3;      salemanHandler.handle(discount);    }  }  

输出:

Saleman Discount ==>  0.95  SaleManager Discount ==>  0.88  AreaManager Discount ==>  0.75  折扣太低,真不能賣了~~

三、小结

一个常见的责任链模式的代码是javax.servlet.Filter#doFilter()。我们可以编写多个Filter,然后形成FilterChain来处理。

责任链模式能够降低耦合度,使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”的处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需要知道链的结构。他们仅需保持一个指向其后继的引用,而不需保持它所有的候选接收者的引用。

当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的添加或修改来增加或者修改处理一个请求的的那些职责。

同时也带来了一个问题,既然一个请求没有明确的接收者,那么就不能保证它一定会被处理。该请求可能一直在链的末端都得到不到处理,一个请求也可能因链没有被正确配置而得不到处理。