抽象工厂模式在go中不用interface{}做返回类型,因其会丢失类型信息、迫使运行时断言,违背接口契约;应为每类产品定义明确接口(如button、checkbox),工厂方法返回对应接口类型,确保编译期类型安全与多态使用。

抽象工厂模式在 Go 里为什么不用 interface{} 做返回类型
Go 没有传统面向对象的“类继承”,抽象工厂的核心不是“创建父类引用”,而是“封装一组相关对象的创建逻辑”。用 interface{} 会丢失类型信息,迫使调用方反复断言,违背接口即契约的设计初衷。
正确做法是为每类产品定义明确的接口(如 Button、Checkbox),工厂方法返回对应接口类型。这样既保证编译期类型安全,又支持多态使用。
- 工厂函数签名应类似:
func CreateButton() Button,而非func CreateButton() interface{} - 不同具体工厂(如
WindowsFactory、MacOSFactory)各自实现同一组接口的构造逻辑 - 客户端代码只依赖
Button和Checkbox接口,不感知具体实现
如何避免工厂实例化时的重复判断逻辑
常见错误是写一个“万能工厂函数”,里面用 switch 或 if/else 判断平台类型再返回不同结构体——这会让工厂本身变得臃肿且难以测试。
推荐做法是让具体工厂类型承担创建职责,抽象工厂只定义行为契约:
立即学习“go语言免费学习笔记(深入)”;
- 定义抽象工厂接口:
type GUIFactory interface { CreateButton() Button; CreateCheckbox() Checkbox } - 每个平台实现该接口:
type WindowsFactory struct{}+ 实现方法 - 初始化时由配置或参数决定构建哪个具体工厂:
var factory GUIFactory = &WindowsFactory{}
这样新增平台只需加一个新结构体和实现,不改动原有工厂逻辑,符合开闭原则。
原本这个程序只是本人两年前初学时练手的,最近拿出来进行了修改,所以叫XmxCms 企业网站管理系统2.0 开发环境:WinXP + VS2008 + SQLServer 2008 + Access开发语言:C#本程序采用 三层架构 + 抽象工厂设计模式 + Linq 实现,目前只做了Access 和 SQL Server ,默认数据库为Access,要更换数据库只需修改web.config 即可
为什么 Go 的抽象工厂常配合依赖注入使用
Go 中没有运行时反射自动装配能力,工厂返回的对象如果直接 new 出来,会导致硬编码依赖,难以 mock 测试。
实际项目中,抽象工厂常作为依赖项传入业务结构体,例如:
type Dialog struct {
factory GUIFactory
}
func (d *Dialog) Render() {
btn := d.factory.CreateButton()
chk := d.factory.CreateCheckbox()
// ...
}
- 测试时可传入 fake 工厂,返回预设的 mock 对象
- 生产环境通过配置选择具体工厂,解耦创建逻辑与使用逻辑
- 若搭配 Wire 或 Dig 等 DI 框架,还能自动绑定
GUIFactory到具体实现
抽象工厂和普通工厂函数的区别在哪
关键差异在于“产品族”约束:抽象工厂强制你一次创建多个**相互兼容**的对象(比如 Windows 风格的按钮 + 复选框),而单个工厂函数只解决单一类型创建问题。
容易踩的坑是把抽象工厂写成一堆独立工厂函数的集合——这失去了模式本意。必须确保:
- 所有
CreateXxx()方法出自同一个工厂实例 - 不同工厂实现之间保持产品风格一致性(如
WindowsFactory.CreateButton()和WindowsFactory.CreateCheckbox()返回的对象共享颜色/尺寸/交互逻辑) - 客户端调用时不混用不同工厂的产品(比如不能拿
MacOSFactory.CreateButton()和WindowsFactory.CreateCheckbox()一起用)
这个约束在 UI 框架或跨平台 SDK 中特别关键,但也是最容易被忽略的一环——很多 Go 项目写着写着就退化成多个独立构造函数了。









