电话
400 9058 355
Go工厂模式用接口+函数返回具体实例解耦创建与使用,应返回明确接口而非interface{},通过注册表替代if/else,支持选项函数或配置结构体传参,注册需线程安全,工厂应轻量无副作用。
Go 语言没有类和继承,所谓“工厂模式”不是靠抽象基类+子类实现的,而是用接口 + 函数返回具体结构体实例的方式达成——核心是解耦创建逻辑与使用逻辑。
工厂函数返回 interface{} 是常见误区。正确做法是返回一个明确的接口类型(比如 Shape),让调用方只依赖行为契约,不感知具体结构体。返回 interface{} 会丢失类型信息,后续必须强制类型断言,反而增加耦合和 panic 风险。
实际做法:
type Shape interface { Area() float64 })func NewShape(kind string) Shape,而非 func NewShape(kind string) interface{}
Circle、Rectangle)实现该接
当产品种类增多,if kind == "circle" { return &Circle{} } 这类硬编码分支会难以维护。更可持续的做法是用注册表 + 映射:
示例关键结构:
var creators = make(map[string]func() Shape)
func Register(name string, creator func() Shape) {
creators[name] = creator
}
func NewShape(kind string) Shape {
if c, ok := creators[kind]; ok {
return c()
}
panic("unknown shape: " + kind)
}
使用时提前注册:
func init() {
Register("circle", func() Shape { return &Circle{} })
Register("rect", func() Shape { return &Rectangle{} })
}
如果具体类型初始化需要参数(比如 Circle{Radius: 5.0}),工厂函数不应直接接收原始字段(如 func NewCircle(radius float64) Shape),否则每新增字段都要改签名。推荐两种方式:
type Option func(*Circle),工厂接收变长 Option 参数,内部按需应用type CircleConfig struct { Radius float64; Unit string },工厂接收 CircleConfig,保持函数签名稳定避免把 map[string]interface{} 当万能参数传入工厂——它绕过了编译检查,运行时易出错且无法被 IDE 提示。
注册表(如上文的 creators map)若在运行时动态注册,多个 goroutine 同时调用 Register 会引发 panic。必须加锁或限定仅在 init() 中注册。
工厂函数本身通常是无状态的,但若内部缓存了资源(如复用连接池、预分配对象池),就要注意:
sync.RWMutex 或 sync.Map)多数情况下,工厂就该是个轻量、纯内存、无副作用的构造函数——复杂初始化逻辑应该下沉到具体类型的 NewXXX() 方法里,而不是塞进工厂分支中。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...