go中工厂模式的核心是用interface+构造函数+显式类型分发解耦创建与使用,避免硬编码实例导致强耦合、难测试、重复校验等问题,分为简单工厂(字符串分发)和注册表工厂(动态注册),需注意接收者类型、nil安全及职责分离。

Go 里用工厂模式管理不同类型实例,核心不是“模仿 Java 写法”,而是用 interface + 构造函数 + 显式类型分发来解耦创建与使用。它不靠继承,靠行为契约和组合,写对了很轻量,写错了容易绕进“接口嵌套”或“空指针 panic”的坑。
为什么不能直接 new 结构体?
硬编码 &Dog{} 或 FileLogger{} 会让调用方和具体类型强耦合。一旦新增日志类型(比如 HTTPLogger),所有调用点都得改;测试时也无法轻松 mock;更麻烦的是,如果某类需要初始化参数(如文件路径、网络地址),分散在各处 new 就会重复校验逻辑。
工厂函数把“怎么造”收口到一处,调用方只认 Logger 接口,不关心背后是 console 还是 file —— 这才是 Go 式解耦的起点。
简单工厂:用字符串参数分发最常用
适合类型不多、扩展不频繁的场景(比如日志、消息序列化器、数据库驱动选择)。关键点是:返回统一接口,构造函数负责内部初始化,工厂函数只做 switch 分发。
-
NewLogger接收type string参数,返回Logger接口 - 每个具体类型(
ConsoleLogger、FileLogger)提供自己的构造函数,比如NewFileLogger(filename string),工厂里调用它,而不是直接字面量构造 - 避免在 switch 里写
return FileLogger{filename: "a.log"}—— 这样会漏掉构造逻辑(比如检查文件可写),也破坏封装 - 错误处理要明确:
default分支别用panic,返回nil加 error 更利于上层判断
工厂方法:按需注册,避免修改已有代码
当类型越来越多,或者来自不同包(比如第三方插件),硬写 switch 就不可持续。这时用注册表模式:用 map[string]func() Logger 存构造函数,Create 函数查表调用。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
典型结构:
var loggerFactories = make(map[string]func() Logger)
func RegisterLogger(name string, f func() Logger) {
loggerFactories[name] = f
}
func CreateLogger(name string) (Logger, error) {
f, ok := loggerFactories[name]
if !ok {
return nil, fmt.Errorf("unknown logger type: %s", name)
}
return f(), nil
}
好处是:新类型只需在自己包的 init() 函数里调用 RegisterLogger("http", NewHTTPLogger),主工厂完全不用动。缺点是全局 map 有并发风险,生产环境要用 sync.RWMutex 保护。
容易忽略的细节:指针 vs 值接收者、nil 安全、初始化失败
Go 工厂最容易翻车的地方不在结构,而在细节:
- 接口方法绑定的是指针还是值接收者,决定了你该返回
&T{}还是T{}。比如func (l FileLogger) Log(...)是值接收者,那FileLogger{}可以直接实现接口;但若方法改成了func (l *FileLogger) Log(...),就必须返回&FileLogger{},否则编译报错 - 构造函数别返回 nil 接口。比如
func NewFileLogger(path string) Logger里如果os.Open失败,不能默默返回nil—— 调用方logger.Log("msg")会 panic。应该拆成func NewFileLogger(path string) (*FileLogger, error),工厂里先检查 error 再包装 - 别让工厂函数承担太多职责:验证参数、加载配置、连接远程服务……这些应该放在构造函数内部,工厂只管“选哪个构造函数”,否则工厂会越来越重,违背单一职责
真正难的从来不是写出一个能跑的工厂,而是让新增类型不碰现有代码、让错误路径清晰可测、让 nil 不在运行时突然出现。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










