设计模式知识体系概览
问题
Go 中常用哪些设计模式?和传统 OOP 语言有什么不同?
答案
Go 设计模式特点
Go 没有类和继承,设计模式的实现方式和 Java/C++ 有显著差异:
| 特点 | 对设计模式的影响 |
|---|---|
| 接口隐式实现 | 不需要 implements,鸭子类型 |
| 没有继承 | 用组合代替继承 |
| 一等函数 | 很多模式可用函数/闭包简化 |
| 包级封装 | 没有 public/private 类,用大小写控制 |
| goroutine | 并发模式比传统 OOP 更简洁 |
常用模式一览
Go 最重要的设计模式
选项模式(Functional Options) 是 Go 社区最具特色的模式,在标准库和知名开源项目中广泛使用。面试高频。
模式与 Go 实现方式对照
| 模式 | Java 实现 | Go 实现 |
|---|---|---|
| 单例 | double-check lock | sync.Once |
| 工厂 | Factory class | 工厂函数 NewXxx() |
| 策略 | Strategy interface | 函数类型参数 |
| 观察者 | Observer interface | channel / callback |
| 装饰器 | Decorator class | 函数包装 |
| 代理 | Proxy class | 接口 + 结构体包装 |
| 迭代器 | Iterator interface | channel / closure |
| 建造者 | Builder class | 选项模式 |
常见面试问题
Q1: Go 为什么不需要依赖注入框架?
答案:
- 显式依赖:Go 推崇在
main函数中手动组装依赖,代码清晰 - 接口隐式实现:不需要注册容器,传入满足接口的任何实现即可
- 代码生成:需要 DI 时用 Wire(编译时生成代码,非运行时反射)
// Go 风格:显式传递依赖
func main() {
db := setupDB()
repo := NewUserRepo(db)
svc := NewUserService(repo)
handler := NewUserHandler(svc)
}
Q2: Go 中 "组合优于继承" 怎么体现?
答案:通过结构体嵌入(embedding) 实现代码复用:
type Logger struct{}
func (l *Logger) Log(msg string) { fmt.Println(msg) }
type UserService struct {
Logger // 嵌入 Logger,获得 Log 方法
repo UserRepo
}
svc := &UserService{}
svc.Log("hello") // 直接调用嵌入类型的方法