为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

    在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

    如果觉得上面的描述很官方,直接看下面的例子。

    在物流系统里,我们有三个核心的功能:物流分配、物流下单和物流面单。请求进来,首先经过分配,然后下单和打印面单,这是一个完整的请求链路。如果分配成功,后面的下单失败,那么下一次请求会直接通过分配,进行下单。也就是每一个service都有一套自己的过滤机制。
    image.png

    定义一个抽象类

    1. public abstract class Handler {
    2. // 后继节点的引用
    3. protected Handler successor;
    4. public abstract void apply(OrderFlowContext context);
    5. public Handler setSuccessor(Handler successor) {
    6. this.successor = successor;
    7. return this;
    8. }
    9. public Handler getSuccessor() {
    10. return successor;
    11. }
    12. }

    物流分配类

    1. public class CarrierAllocateService extends Handler{
    2. @Override
    3. public void apply(OrderFlowContext context) {
    4. //根据context内容处理逻辑
    5. //处理完成,沿着链路调用下一个service
    6. getSuccessor().apply(context);
    7. }
    8. }

    物流下单类

    1. public class CarrierPlaceOrderService extends Handler{
    2. @Override
    3. public void apply(OrderFlowContext context) {
    4. //根据context内容处理逻辑
    5. //处理完成,沿着链路调用下一个service
    6. getSuccessor().apply(context);
    7. }
    8. }

    物流面单类

    1. public class CarrierExpressService extends Handler {
    2. @Override
    3. public void apply(OrderFlowContext context) {
    4. //根据context内容处理逻辑
    5. //处理完成,沿着链路调用下一个service
    6. getSuccessor().apply(context);
    7. }
    8. }

    关于context
    context相当于一个容器,存储一些基本信息和结果。为每一次service逻辑运算提供数据,也可以存储service的结果,供下一个service使用。根据实际的业务去定义context内容。

    使用:

    1. carrierAllocateService.setSuccessor(carrierPlaceOrderService.setSuccessor(carrierExpressService)).apply(context);