go中抽象工厂模式本质是用interface定义产品契约、结构体实现具体产品、函数或闭包封装创建逻辑,核心在于解耦产品族创建与使用,而非模拟java抽象类;需避免字符串key、类型断言和reflect滥用,强调编译期安全与单一职责。

Go 语言没有传统面向对象意义上的“抽象工厂”——它没有继承、没有抽象类、也没有接口的实现强制约束。所谓“抽象工厂模式”的 Go 实现,本质是用 interface 定义契约,用普通结构体和函数组合来封装创建逻辑,关键不在“模拟 Java 写法”,而在“用 Go 的方式解决多态创建问题”。
为什么 Go 里不能直接写 abstract factory?
Go 不支持方法重载、不支持类继承、interface 是隐式实现且无法定义构造函数。你写不出 abstract class AbstractFactory 这样的东西,强行套用只会导致冗余 wrapper 和难以维护的类型断言。
- 所有“工厂”在 Go 中最终都落地为一个返回具体类型的函数或闭包,比如
func() Shape或func(color string) Drawer -
interface{}不是解决方案——它放弃编译期类型安全,后续必须.(*Concrete)断言,极易 panic - 所谓“抽象”,应体现在
interface定义的行为契约上(如Draw()),而不是工厂本身的“抽象类”层级
如何用 interface + struct 实现可扩展的工厂?
核心是把“产品族”行为抽成 interface,把“工厂行为”抽成函数签名,再用 map 或 switch 分发。例如要支持不同渲染后端(SVG / Canvas)下的图形(Circle / Rect):
// 产品接口
type Shape interface {
Draw() string
}
type SVGRenderer struct{}
func (SVGRenderer) DrawCircle() string { return "<circle>" }
func (SVGRenderer) DrawRect() string { return "<rect>" }
type CanvasRenderer struct{}
func (CanvasRenderer) DrawCircle() string { return "ctx.arc(...)" }
func (CanvasRenderer) DrawRect() string { return "ctx.rect(...)" }
// 工厂函数:按 renderer 类型返回对应 Shape 构造器
type ShapeFactory func() Shape
var factories = map[string]ShapeFactory{
"svg": func() Shape { return &SVGCircle{} },
"canvas": func() Shape { return &CanvasCircle{} },
}
</rect></circle>
- 不要试图让一个工厂返回多种产品(Circle + Rect),那会破坏单一职责;每个工厂只负责一种产品线的实例化
- 如果需要“族”级控制(比如 SVG 下必须配 SVGCircle + SVGRect),用闭包捕获 renderer 实例更自然:
func(r SVGRenderer) CircleFactory() Shape - 避免用字符串做 key,改用自定义类型如
type RendererType string,并定义常量const SVG RendererType = "svg"
常见错误:把 new() 或 reflect 当成工厂核心
看到 reflect.New() 就以为能动态创建任意类型?这会绕过编译检查、丢失泛型约束、且性能差。真实项目中几乎不需要。
-
new(T)只分配零值内存,不调用任何初始化逻辑(比如字段校验、依赖注入),不能替代构造函数 - 用
map[string]interface{}存一堆工厂函数?类型信息全丢,调用时还得手动断言,跟不用 interface 没区别 - 误以为 “factory method” 必须是方法——Go 里最清晰的工厂就是普通函数,比如
func NewUserDB(cfg DBConfig) *UserDB
真正难的不是写出工厂函数,而是判断哪些对象值得被工厂封装:是否有多套实现?是否创建逻辑复杂(需校验、依赖注入、资源预分配)?是否测试时需要 mock?这些才是驱动你引入工厂的信号,而不是模式目录里的名字。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











