设计模式 35:协作集中会形成大对象吗
金额审核要同时请财务与库存给出意见。旧版 Finance.approve() 自己直接创建并调用 Stock,财务组件知道库存组件的类型;新增审计参与方时,这段相互依赖会更难改。但把所有判断都放到一个“总审批器”里,也可能只是造出新的大对象。
集中路由,不集中所有规则
labs/35 的 Before 让财务知道库存,500 分时两者通过,轨迹为 finance, stock。After 的协调者只保存一份参与者列表、按注册顺序请求每人检查、汇总布尔结果;财务是否允许非正金额、库存是否允许超过 1000 分仍由各自的 Participant 决定。对 0 分,协调者仍向两人征求意见,返回失败并留下两条轨迹;这不是责任链遇失败就停止。新增一个审计参与者只需加入列表,本章断言 500 分被审计拒绝、100 分仍通过,旧财务与库存的实现不修改。
1 | |
这里先求 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 分边界均用断言而非打印验证。
- 新增“审计参与者只拒绝 500 分以上”的规则,先在两位原参与者的测试中锁定旧轨迹,再添加第三位的拒绝/批准断言,确保旧组件不互相引用。
- 假设始终只有财务和库存,删除注册列表改用
Alternative;复跑全部旧结果与两位都被调用的轨迹测试,指出何时协调者才值得引入。
参考资料
- GoF 原书公开图书馆 PDF,5.5 Mediator,目录页标注起始页 305:https://cpcc.chd.gov.in/Content/PDFs/w8UkV3tWNyEtsbUZSWJ7fVhuB9A3tsGYdm4w6VGzg2wUTNFYikqnvvFbbkiW2zmfspPEghd7QTamiMby3lVIBemrhdVWwt6rOQnm.pdf 。
- Mediator 模式简定义,InfoWorld/JavaWorld:https://www.infoworld.com/article/2170730/design-patterns-the-big-picture-part-1-design-pattern-history-and-classification.html 。
- 本篇来源边界:
writing-plans/design-patterns/SOURCES.md。 - 实验代码:
examples/design-patterns/labs/35/。
上一节:34 遍历协议隐藏了什么;下一节:36 快照如何限制内存与别名。






