Golang设计模式是什么_Golang常见设计模式解析

10次阅读

sync.Once 是 go 单例模式的唯一正解,因其轻量可靠且专为懒加载设计;NewXXX() 是 Go 工厂模式事实标准,应配合选项模式与延迟初始化;装饰器即 http.Handler 闭包链;观察者优先用 channel 或消息队列;单例须谨慎使用,避免阻碍测试与资源管理。

Golang设计模式是什么_Golang常见设计模式解析

sync.Once 是 Go 里单例模式的唯一正解,不是“一种可选方案”,而是事实标准。其他写法——比如手写双重检查锁、包级变量裸用、或在 GetInstance() 里加 mutex——要么错,要么冗余,要么埋雷。

为什么不用自己加锁做单例?

Go 的包初始化天然串行,var instance = &MyService{}init() 里就足够安全;但若初始化依赖运行时配置(比如读环境变量、加载 YAML),就必须懒加载,这时 sync.Once 是唯一轻量又可靠的机制。
常见错误现象:
• 在 GetInstance() 外层加 if instance == nil 判断再调 once.Do,导致并发下可能返回零值
• 把整个方法体都锁住,而不是只锁初始化逻辑,严重拖慢吞吐
• 返回结构体而非指针,造成意外拷贝,破坏单例语义

NewXXX() 就是 Go 的工厂模式,别抽象出 Creator 接口

Go 没有构造函数重载,也没有抽象类,所谓“工厂”就是一组命名规范的构造函数NewDB()NewLogger()NewHTTPClient()。它们封装创建逻辑、校验参数、返回接口,就够了。
实操建议:
• 参数用选项模式(func(*Client) Error)替代长参数列表,比如 NewHTTPClient(WithTimeout(5*time.Second), WithRetry(3))
• 工厂函数里不做 I/O(如连接数据库),只负责构造;真正初始化放 Start()Init() 方法里
• 新增驱动类型时,优先用注册表方式(RegisterRepo("mysql", func() Repo {...})),避免 switch 垃圾场

装饰器模式 = HTTP 中间件式闭包,不是语法糖

Go 没有装饰器关键字,但 func(http.Handler) http.Handler 这个签名就是事实标准。所有横切逻辑(日志、鉴权、熔断)都该遵循它,靠链式组合实现。
关键点:
• 不要试图给结构体方法加装饰器——那是面向对象思维残留;Go 里装饰的是行为,不是对象
• 中间件必须接收并返回 http.Handler,不能只收 http.HandlerFunc,否则无法兼容自定义 handler 类型
• 错误处理要显式透传:不要在中间件里 panic,也不要吞掉下游 WriteHeader 调用

观察者模式在 Go 里首选 channel 或消息队列,慎用内存注册表

sync.map 存一 func(Event) 回调听着像教科书,实际项目中几乎没人这么干。高频事件(如指标打点)直接走 chan Event;业务级通知(如订单创建)走 NATS / redis PubSub;只有单实例且订阅者极少时,才考虑内存回调。
容易踩的坑:
• 在 Notify() 里同步遍历所有回调,一个卡住全卡住
• 订阅者没做 recover,panic 波及整个通知流程
• 忘记关闭 channel 或未处理已退出 goroutine 的残留监听

立即学习go语言免费学习笔记(深入)”;

真正难的不是“怎么写单例”,而是判断“该不该用单例”。全局配置、指标注册器可以,但 DB 连接池、HTTP 客户端、日志器——这些都应该通过依赖注入传递,否则测试没法 mock,生命周期无法控制,服务重启时资源清理顺序也会失控。

text=ZqhQzanResources