sync.once 是确保初始化只执行一次且线程安全的唯一正确方式,初始化逻辑必须全部置于 once.do 闭包内,返回指针类型,并将校验逻辑一并包含其中。

sync.Once 是单例模式的唯一安全写法
别手写双重检查锁,Go 里没有“类加载时机”这种保障,sync.Once 是唯一能确保初始化只执行一次且线程安全的机制。自己用 mutex 加锁不仅容易漏掉读锁、导致并发读到零值,还多出不必要的性能开销。
常见错误现象:GetConfig() 返回的 *Config 字段为零值(比如 Port 是 0),但日志显示初始化逻辑已执行过——这说明初始化被提前赋值,没包在 once.Do() 闭包里。
- 初始化逻辑必须全部放在
once.Do(func(){...})闭包内,不能在外面先 new 再赋值 - 返回类型必须是指针(
*Config),否则结构体拷贝会破坏单例语义 - 如果初始化依赖环境变量或配置文件,校验逻辑(如端口范围检查)也得放进去,失败时 panic 或 log.Fatal 都比返回无效实例更安全
NewXXX 构造函数就是 Go 的工厂模式
Go 没有抽象工厂或工厂方法接口的必要。所谓“工厂”,就是一组命名清晰、参数合理的 NewXXX() 函数,配合小而精的 interface 返回,足够覆盖 95% 场景。
使用场景:初始化 HTTP 客户端、数据库连接池、日志器、缓存客户端等需要封装创建细节的对象。
- 参数优先用结构体选项(
type Option func(*Client)),而不是长参数列表,避免调用时传一堆nil - 错误必须显式返回,
NewDB("mysql")如果连接字符串非法,应返回error,而不是 panic - 别为“可插拔”提前抽象出
ClientFactory接口——除非你真要运行时切换 Oracle/PostgreSQL 实现,否则纯属增加调用链和心智负担
装饰器模式 = HTTP 中间件 + 函数包装
Go 里装饰器不是语法糖,而是基于函数类型(type Handler func(http.ResponseWriter, *http.Request))的组合能力。它天然适配中间件链,也是 Web 框架最常复用的模式。
常见错误现象:多个装饰器嵌套后 panic 堆栈难追踪;或在装饰器里直接调用 w.WriteHeader() 导致后续中间件无法修改状态码。
- 每个装饰器必须调用
next(w, r),且应在next前后做对称操作(如计时、日志) - 不要在装饰器里提前写响应体,除非你明确知道这是终结型中间件(如静态文件服务)
- 真实项目中,
LoggingDecorator这类基础装饰器建议带 context 超时控制,避免日志打满磁盘阻塞主线程
观察者模式慎用内存切片,优先走消息队列
在微服务中,用 []Observer 维护监听者列表看似简单,但同步调用 Update() 会导致一个慢 Observer 拖垮整个事件流。生产环境几乎从不这么用。
使用场景:订单创建后通知库存、短信、风控等下游系统;用户登录后广播在线状态变更。
- 内存级观察者仅限单实例、低频、非关键事件(如调试日志广播)
- 跨服务解耦必须走异步通道:NATS、Kafka 或 Redis Pub/Sub,靠
nc.Publish("order.created", data)发布 - 事件结构体字段要稳定,加新字段必须兼容旧消费者,避免用
map[string]interface{}存原始数据
interface + 一组 NewXXX + 若干个装饰器函数,就已经覆盖了大部分需求。过度抽象只会让 go doc 变厚、IDE 补全变慢、新人读三天代码还找不到入口点。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











