Golang简单工厂和抽象工厂有什么区别_工厂模式选择建议

1次阅读

简单工厂是函数式封装,抽象工厂是接口+结构体的多产品族管理机制;前者适用于低频新增、编译期确定类型的场景,后者用于强关联组件的原子性切换。

Golang简单工厂和抽象工厂有什么区别_工厂模式选择建议

简单工厂和抽象工厂在 go 里根本不是“同级概念”:简单工厂是函数式封装,抽象工厂是接口+结构体组合的多产品族管理机制;选错会导致后期加功能时要么疯狂改 NewXXX 函数,要么硬塞不相关的创建逻辑进一个工厂。

什么时候该用 NewPayment 这类简单工厂?

当你只有一组同类对象(比如所有支付方式都实现 Payment 接口),且新增类型频率低、无需运行时动态注册时,用函数最轻量。

  • 典型场景:log.NewLogger("file")cache.NewClient("redis")db.NewConnection("mysql")
  • 参数必须是编译期可确定的字符串或枚举,不能靠配置文件热加载新类型
  • 一旦新增支付方式(如 PayPal),就得改 switch 分支 —— 违反开闭原则,但小项目够用
  • 别返回具体结构体指针(如 *Alipay),始终返回接口(Payment),否则调用方会意外依赖实现细节

为什么 UIFactory 接口必须定义多个创建方法?

抽象工厂的核心约束是“一组相关对象的原子性创建”,比如 windows 下的 Buttoncheckbox 必须配套使用,不能混搭 macos 的控件。所以工厂接口要强制声明整套能力。

  • CreateButton()CreateCheckbox() 必须由同一个具体工厂实现,确保风格/行为一致
  • 新增操作系统支持(如 linux GUI)只需实现新结构体(LinuxFactory),完全不碰老代码
  • 如果只想要按钮,却仍得实现 CreateCheckbox()(哪怕返回 nil),说明你误用了抽象工厂——该换回简单工厂或工厂方法
  • Go 中没有抽象类,所以用 type UIFactory Interface { ... } + 具体结构体实现,而非继承

想支持插件化扩展?别写死 switch,用注册表代替

简单工厂的硬编码分支是最大瓶颈;抽象工厂又太重。折中方案是“带注册机制的工厂函数”,既保持函数调用简洁,又满足运行时扩展。

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

  • map[String]func() Payment构造函数,而不是 switch 判断字符串
  • init() 或模块加载时调用 RegisterPayment("paypal", func() Payment { return &PayPal{} })
  • CreatePayment(name) 查表失败直接 panic 或返回 Error,避免静默失败
  • 注意并发安全:如果注册发生在多个 goroutine,需加 sync.RWMutex,但初始化阶段通常单线程,可省略
var paymentRegistry = map[string]func() Payment{}  func RegisterPayment(name string, creator func() Payment) {     paymentRegistry[name] = creator }  func CreatePayment(name string) Payment {     creator, ok := paymentRegistry[name]     if !ok {         panic("unknown payment method: " + name)     }     return creator() }

抽象工厂真正发挥作用的地方,是当你需要同时切换多个强关联组件(比如「国内版支付+短信通知」vs「国际版支付+邮件通知」),而简单工厂连这种组合关系都表达不了。别为了设计模式而设计模式——先画清楚你的产品矩阵,再决定用哪一层工厂。

text=ZqhQzanResources