中介者模式在go中需自行定义mediator接口,仅包含必要协调方法;结构体应依赖服务接口而非具体实例,避免直接调用http或db;禁用sync.map缓存状态,优先使用sync.rwmutex保护普通map;测试须结合集成验证时序与分布式行为。

中介者模式在 Go 里没有 Mediator 接口,得自己定义行为契约
Go 没有抽象类或接口继承树的强制约束,所谓“中介者”只是结构体 + 方法集合。你不能指望 go run 或 go vet 告诉你漏实现了哪个协调逻辑——它只认方法签名是否匹配接口。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 先定义一个
Mediator接口,只包含服务间真正需要委托的动作,比如NotifyUserChanged()、RouteOrderToInventory(),别塞一堆泛用方法 - 中介者结构体里不要存具体服务实例指针(如
*UserService),改用接口(如UserNotifier),否则单元测试时没法 mock - 避免让中介者直接调用 HTTP 客户端或数据库——这些该由具体服务封装,中介者只做决策和转发
微服务间通信走中介者,但别把 HTTP 或 Kafka 调用塞进中介者方法里
常见错误是把中介者写成“胶水函数”:一个 ProcessOrder() 方法里既发 POST /inventory/lock,又推 Kafka 消息,还查本地缓存。结果一出错,根本分不清是网络超时、序列化失败,还是业务规则没校验。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 中介者只负责编排顺序和条件分支,例如:“若库存服务返回
InsufficientStockError,则触发补偿流程”,而不是亲自发请求 - 每个下游服务暴露的客户端必须自带重试、超时、熔断(用
github.com/sony/gobreaker或resilience-go),中介者不重复实现 - 如果用
Kafka,中介者只调用producer.Send(),不处理DeliveryReport回调——那是消费者或监控模块的事
用 sync.Map 缓存中介者状态?小心并发读写和 GC 压力
有人在中介者里用 sync.Map 存“当前订单路由状态”或“会话活跃节点列表”,结果压测时发现内存涨得快、GC 频繁,甚至出现 key 漏删——因为 sync.Map 的 Range 不保证原子性,遍历时删 key 会丢数据。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 除非明确需要高频并发读+低频写,否则优先用带锁的普通
map+sync.RWMutex,更可控、更易 debug - 缓存值别存大结构体指针,尤其含
http.Client或未关闭的sql.Rows,容易泄漏 - 如果真要用
sync.Map,写操作统一走LoadOrStore(),读操作别依赖Range()做业务逻辑,改用定时器 + 单独 goroutine 清理过期项
测试中介者逻辑时,gomock 或 testify/mock 很难覆盖真实拓扑行为
单元测试里 mock 掉所有下游服务后,看似覆盖率 100%,但上线才发现:中介者在分布式时序下会重复发消息、漏触发回调、或因时钟漂移误判超时——这些只有集成测试能暴露。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 单元测试只验证中介者内部分支逻辑(如 “当 order.Status == 'paid' 且 inventory.Available compensate()”)
- 用
docker-compose启三个轻量服务(哪怕只是 echo server),跑真实 HTTP 请求链路,重点测context.WithTimeout传递、header 透传、错误码映射 - 别 mock
time.Now()—— 改用注入clock Clock接口,测试时可快进时间验证超时路径
中介者最难的不是写转发逻辑,而是界定“它该知道什么”和“它绝不该碰什么”。边界模糊了,很快就会变成新的上帝对象,只是名字好听点而已。










