装饰器模式适合横切逻辑,需透传context.context;模板方法适用于固定流程+可变步骤,靠接口+组合实现;facade用于整合子系统但忌变成上帝对象;gorm事务须精确控制粒度。

装饰器模式适合横切逻辑,但必须透传 context.Context
Go 没有语法级装饰器,但用高阶函数(如 WithTimeout、WithLogging)封装日志、超时、重试等通用行为,是最轻量且类型安全的做法。关键不是“看起来像 Python”,而是确保上下文不丢失。
-
context.Context必须作为第一个参数透传进所有被包装的函数,否则ctx.Done()、ctx.Value()全部失效 - 错误要用
fmt.Errorf("xxx: %w", err)包装,不能直接return errors.New(...),否则错误链断裂 - 链式调用顺序直接影响执行流:
WithMetrics(WithTimeout(5*time.Second)(handler))中,WithMetrics最先执行、最后返回 - 避免在闭包里捕获可变变量(比如循环中的索引),否则所有装饰器共享同一份值
模板方法模式适合固定流程+可变步骤,靠接口+组合实现
当业务流程骨架稳定(如“准备→处理→写入→完成”),但中间步骤因格式/渠道不同而变化时,用接口定义可变行为,结构体封装不变流程,比 if-else 或 switch 更易扩展。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 定义接口只暴露需要定制的方法,例如
Exporter.ProcessData()和Exporter.WriteToFile() - 模板结构体(如
DataExporter)不实现业务逻辑,只调用接口方法并控制执行顺序 - 新增导出方式只需实现接口,无需修改模板结构体或调用方代码
- 注意:不要让模板结构体持有具体实现的强引用(比如在
prepareData()里调用exporter.WriteToFile()),否则破坏职责分离
Facade 模式用于整合多子系统协作,但别让它变成上帝对象
电商下单这类场景涉及用户、库存、支付、通知多个子系统,用 Facade 提供单一入口能大幅降低调用方复杂度,但容易滑向“大杂烩”反模式。
- Facade 结构体应只组合已有接口(如
UserManager、InventoryService),不做新逻辑,更不存状态 - 每个方法尽量保持原子性:比如
PlaceOrder()内部按需调用子系统,但不暴露子系统细节,也不允许外部绕过 Facade 直接调用底层 - 避免把事务控制、重试、缓存等横切逻辑塞进 Facade;这些该由装饰器或中间件处理
- 如果 Facade 方法开始出现大量条件分支(如根据订单类型走不同路径),说明它已承担过多职责,该拆分或引入策略模式
GORM 工作流天然支持复杂业务,但事务粒度必须精确
GORM 的 Callbacks 和 Transaction 机制让数据库层具备流程编排能力,但开发者常误以为“套个 db.Transaction 就万事大吉”。实际中,事务边界错位是数据不一致的主因。
- 不要在 HTTP handler 层包裹整个业务流程的事务;应下沉到 service 层,按业务原子性拆分,比如“扣库存 + 记订单”是一次事务,“发通知”是另一件事
- 使用
BeforeCreate/AfterUpdate钩子时,避免在钩子里调用外部服务(如发短信),失败会导致事务回滚不可控 -
db.Session(&gorm.Session{NewDB: true})可隔离会话状态,适合并发场景下避免事务污染,但别滥用——每次新建 session 都有开销 - 批量操作(如
CreateInBatches)自带事务,但默认不触发BeforeCreate等钩子,需手动启用
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










