1. 意图(Intent)

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

责任链通常需要先建立一个单向链表,然后调用方只需要调用头部节点就可以了,后面会自动流转下去。

比如流程审批就是一个很好的例子,只要终端用户提交申请,根据申请的内容信息,自动建立一条责任链,然后就可以开始流转了。

2. 类图(Class Diagram)

  • Handler:定义处理请求的接口,并且实现后继链(successor)

ca9f23bf-55a4-47b2-9534-a28e35397988 (1).png

3. 实现(Implementation)

I 校验规则案例

首先,我们要定义流程上节点的基类:

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

接下来,我们需要定义具体的每个节点了。
校验用户是否是新用户:

public class NewUserRuleHandler extends RuleHandler {
    public void apply(Context context) {
        if (context.isNewUser()) {
            // 如果有后继节点的话,传递下去
            if (this.getSuccessor() != null) {
                this.getSuccessor().apply(context);
            }
        } else {
            throw new RuntimeException("该活动仅限新用户参与");
        }
    }
}

校验用户所在地区是否可以参与:

public class LocationRuleHandler extends RuleHandler {
    public void apply(Context context) {
        boolean allowed = activityService.isSupportedLocation(context.getLocation);
        if (allowed) {
            if (this.getSuccessor() != null) {
                this.getSuccessor().apply(context);
            }
        } else {
            throw new RuntimeException("非常抱歉,您所在的地区无法参与本次活动");
        }
    }
}

校验奖品是否已领完:

public class LimitRuleHandler extends RuleHandler {
    public void apply(Context context) {
        int remainedTimes = activityService.queryRemainedTimes(context); // 查询剩余奖品
        if (remainedTimes > 0) {
            if (this.getSuccessor() != null) {
                this.getSuccessor().apply(userInfo);
            }
        } else {
            throw new RuntimeException("您来得太晚了,奖品被领完了");
        }
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        RuleHandler newUserHandler = new NewUserRuleHandler();
        RuleHandler locationHandler = new LocationRuleHandler();
        RuleHandler limitHandler = new LimitRuleHandler();

        // 假设本次活动仅校验地区和奖品数量,不校验新老用户
        locationHandler.setSuccessor(limitHandler);

        locationHandler.apply(context);
    }
}

先定义好一个链表,然后在通过任意一节点后,如果此节点有后继节点,那么传递下去。

至于它和我们前面说的用一个 List 存放需要执行的规则的做法有什么异同,留给读者自己琢磨吧。

II 处理规则案例

[ Handler ]

public abstract class Handler {

    protected Handler successor;

    public Handler(Handler successor) {
        this.successor = successor;
    }

    protected abstract void handleRequest(Request request);
}

[ ConcreteHandler ]

public class ConcreteHandlerA extends Handler {

    public ConcreteHandler1(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE1) {
            System.out.println(request.getName() + " is handle by ConcreteHandlerA");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
public class ConcreteHandlerB extends Handler {

    public ConcreteHandler2(Handler successor) {
        super(successor);
    }

    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE2) {
            System.out.println(request.getName() + " is handle by ConcreteHandlerB");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}
@Get
public class Request {

    private RequestType type;
    private String name;
    //...设置 Get 函数

    public Request(RequestType type, String name) {
        this.type = type;
        this.name = name;
    }
}
public enum RequestType {
    TYPE1, TYPE2
}

客户端:

public class Client {

    public static void main(String[] args) {
        // 处理规则链 ConcreteHandlerB -> ConcreteHandlerA -> null
        Handler handler1 = new ConcreteHandlerA(null);
        Handler handler2 = new ConcreteHandlerB(handler1);

        Request requestA = new Request(RequestType.TYPE1, "requestA");
        Request requestB = new Request(RequestType.TYPE2, "requestB");

        //处理从头部开始处理
        handler2.handleRequest(request1);
        handler2.handleRequest(request2);
    }
}

输出:

request1 is handle by ConcreteHandlerA
request2 is handle by ConcreteHandlerB


4. JDK