如何在Golang中实现工厂模式_Golang工厂模式对象创建示例

17次阅读

go中“工厂函数”是返回接口值的轻量函数,通过接口隐式满足契约,避免冗余Factory结构体;典型如NewLogger根据参数返回不同Logger实现,且工厂函数不应含heavy初始化。

如何在Golang中实现工厂模式_Golang工厂模式对象创建示例

什么是Go里的“工厂函数”而非“工厂类”

Go没有类和继承,所以传统OOP中的抽象工厂、工厂方法模式无法直接套用。Go的工厂模式本质是一组返回接口类型值的函数,靠组合和接口隐式满足契约,不是靠类型系统强制实现。别试图写 Factory 结构体去“new”其他结构体——这反而是冗余设计。

interface + 工厂函数解耦对象创建

典型场景:需要根据配置或参数创建不同行为的 Logger(比如 FileLoggerConsoleLogger),但调用方只依赖 Logger 接口。

  • 先定义统一接口:type Logger Interface { Log(String) }
  • 每个具体实现不暴露字段,只导出构造函数NewConsoleLogger()NewFileLogger(filename string)
  • 工厂函数集中封装判断逻辑,例如:NewLogger(kind string, cfg map[string]string) Logger

这样调用方完全不知道背后是哪个结构体,也不会 import 具体实现包(除非必须传参)。

type Logger interface {     Log(msg string) }  type consoleLogger struct{}  func (c *consoleLogger) Log(msg string) {     fmt.Println("[CONSOLE]", msg) }  func NewConsoleLogger() Logger {     return &consoleLogger{} }  type fileLogger struct {     filename string }  func (f *fileLogger) Log(msg string) {     os.WriteFile(f.filename, []byte(msg), 0644) }  func NewFileLogger(filename string) Logger {     return &fileLogger{filename: filename} }  func NewLogger(kind string, cfg map[string]string) Logger {     switch kind {     case "console":         return NewConsoleLogger()     case "file":         return NewFileLogger(cfg["filename"])     default:         return NewConsoleLogger()     } }

为什么不要在工厂里做 heavy initialization

工厂函数应轻量、无副作用、可测试。如果 NewFileLogger 一调用就打开文件句柄或连接数据库,会导致:

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

  • 单元测试难 mock(你得提前建好真实文件或DB)
  • 对象创建失败时错误难以归因(是参数错?磁盘满?权限不足?)
  • 违反“创建即可用”的直觉——用户拿到 Logger 却不能立刻 Log

正确做法:工厂只组装结构体,把初始化延迟到首次使用(如 Log 内部 lazy open),或拆出显式的 Init() 方法由调用方控制时机。

泛型工厂函数在 Go 1.18+ 的适用边界

泛型能简化“同构类型”的工厂,比如统一创建带缓冲的 channelfunc NewChan[T any](size int) chan T。但它不适合替代接口工厂

常见误用:写 func NewService[T Service]() T —— 这要求 T 必须有零值且可直接返回,丧失了多态能力;也无法隐藏具体实现细节。真正需要多态时,还是得回到 interface{} + 具体构造函数的组合。

泛型工厂只适合“类型参数化但行为一致”的场景,比如容器、工具函数,而不是业务对象的策略替换。

text=ZqhQzanResources