金额审核要同时请财务与库存给出意见。旧版 Finance.approve() 自己直接创建并调用 Stock,财务组件知道库存组件的类型;新增审计参与方时,这段相互依赖会更难改。但把所有判断都放到一个“总审批器”里,也可能只是造出新的大对象。

集中路由,不集中所有规则

labs/35 的 Before 让财务知道库存,500 分时两者通过,轨迹为 finance, stock。After 的协调者只保存一份参与者列表、按注册顺序请求每人检查、汇总布尔结果;财务是否允许非正金额、库存是否允许超过 1000 分仍由各自的 Participant 决定。对 0 分,协调者仍向两人征求意见,返回失败并留下两条轨迹;这不是责任链遇失败就停止。新增一个审计参与者只需加入列表,本章断言 500 分被审计拒绝、100 分仍通过,旧财务与库存的实现不修改。

1
2
3
4
5
6
boolean approved = true;
for (Participant participant : participants) {
boolean result = participant.check(amount, trace);
approved = approved && result;
}
return approved;

这里先求 result 再合取,保证每位参与者都被调用;直接写 approved = approved && participant.check(...) 会因短路跳过后面的协作。本例 Mediator 的价值在“谁与谁通信”不再散在各参与者内部,不是把金额规则全部移入协调者。Alternative 是固定两个参与者时的显式调用函数,可以满足同一旧合同而不维护注册表。若参与者永不变,普通函数更透明;若把所有业务拒绝原因都集中到协调者,容易把它变成另一个难修改的大类。

与 31 的 Observer 不同,这里协调者收集各参与者的返回值并生成一次决策,而不是广播事实后不关心订阅者决策;与 32 的责任链不同,拒绝也不会停止联系其他参与者。异常如何汇总、并发审批或异步等待均未定义。

方案 财务与库存的依赖关系 新增审计参与者
Before 财务直接认识库存实现 修改调用链
After 各规则只受协调者调度 在组装处注册,不改旧规则
Alternative 一个函数明确调用两者 修改本地函数
flowchart LR
    Caller[审批请求方] --> Mediator[After 协调者]
    Mediator --> Finance[Participant 财务规则]
    Mediator --> Stock[Participant 库存规则]
    Mediator --> Audit[Participant 新审计规则]
    Finance --> Result[汇总结果与轨迹]
    Stock --> Result
    Audit --> Result

验证与练习

执行 ./mvnw -B -ntp -pl labs/35 -am test 与累计 ./mvnw -B -ntp verify,环境、轨迹、退出码、原始输出见 examples/design-patterns/evidence/35/RUN.md。正例、反例及 0 分边界均用断言而非打印验证。

  1. 新增“审计参与者只拒绝 500 分以上”的规则,先在两位原参与者的测试中锁定旧轨迹,再添加第三位的拒绝/批准断言,确保旧组件不互相引用。
  2. 假设始终只有财务和库存,删除注册列表改用 Alternative;复跑全部旧结果与两位都被调用的轨迹测试,指出何时协调者才值得引入。

参考资料

上一节:34 遍历协议隐藏了什么;下一节:36 快照如何限制内存与别名。