go中抽象工厂用函数或结构体返回配套接口实例,而非java式接口继承;核心是解耦创建逻辑与保证产品协同,如devfactory()返回devlogger和textformatter;推荐可配置结构体而非全局变量,避免过度抽象,按需提取最小接口。

Go 语言没有类、继承和接口实现的强制约束,所以抽象工厂模式不能照搬 Java/C# 那套“抽象工厂接口 + 具体工厂类 + 产品族接口 + 具体产品类”的写法。它得用 Go 的组合、函数值、接口和结构体字段来等价表达——核心是「解耦产品创建逻辑」和「保证同一工厂产出的产品可协同工作」。
抽象工厂的核心不是接口嵌套,而是工厂函数返回一组有约定关系的实例
在 Go 中,抽象工厂通常表现为一个返回多个接口值的函数或方法,这些接口共同构成一个“产品族”。比如日志模块中 Logger 和 Formatter 必须配套使用,不同环境(dev/staging/prod)需要不同组合:
-
DevFactory()返回&devLogger{}和&textFormatter{} -
ProdFactory()返回&syslogLogger{}和&jsonFormatter{}
关键不是定义一堆空接口,而是让调用方只依赖工厂函数签名,不感知具体类型。例如:
type Logger interface { Log(msg string) }
type Formatter interface { Format(msg string) string }
<p>func DevFactory() (Logger, Formatter) {
return &devLogger{}, &textFormatter{}
}</p><p>func ProdFactory() (Logger, Formatter) {
return &syslogLogger{}, &jsonFormatter{}
}这种写法比定义 type LoggerFactory interface { CreateLogger() Logger; CreateFormatter() Formatter } 更轻量,也更符合 Go 的惯用法。
立即学习“go语言免费学习笔记(深入)”;
原本这个程序只是本人两年前初学时练手的,最近拿出来进行了修改,所以叫XmxCms 企业网站管理系统2.0 开发环境:WinXP + VS2008 + SQLServer 2008 + Access开发语言:C#本程序采用 三层架构 + 抽象工厂设计模式 + Linq 实现,目前只做了Access 和 SQL Server ,默认数据库为Access,要更换数据库只需修改web.config 即可
用结构体字段模拟“工厂实例”,便于传参和测试
当需要把工厂作为依赖注入(比如传给 service 层),直接传函数不如传一个带字段的结构体清晰。常见错误是把工厂做成全局变量,导致测试时无法 mock:
- ❌ 全局工厂:所有测试共享状态,
SetEnv("prod")会影响其他测试 - ✅ 可配置工厂结构体:
type LogFactory struct { Env string },方法(f *LogFactory) NewLogger() Logger内部根据f.Env分支返回
这样单元测试可以构造 &LogFactory{Env: "dev"} 独立验证,不需要改环境变量或重置全局状态。
避免过度抽象:Go 中的“抽象”常靠函数签名和文档约定,而非接口继承树
很多教程强行模仿 Java,为每个产品族定义两层接口(如 Button / MacButton / WinButton),结果导致大量无意义的接口声明和类型断言。Go 更推荐:
- 先写出两个实际可用的产品组合(比如
fileStorage+csvParser和s3Storage+jsonParser) - 观察它们共用的行为,提取最小接口(如
Storer和Parser) - 用工厂函数或结构体方法统一创建配对实例,不强求所有产品都实现“顶层抽象接口”
如果某类产品根本不会被替换(比如内部工具只用 CSV 解析),就别硬加 Parser 接口——抽象的价值在于可变性,不是语法完整性。
真正难的不是写出能编译的工厂代码,而是判断哪些创建逻辑值得封装、哪些组合必须绑定、哪些接口该收敛。Go 不会替你做决策,它只提供足够少的机制,让你把注意力留在业务契约上。









