抽象工厂模式 (Abstract Factory Pattern)

shaojie lishaojie li
4 min read

概述

抽象工厂模式是一种创建型设计模式,它提供了一个接口用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

通俗理解:想象你要买电子设备,苹果工厂只生产苹果产品(iPhone + MacBook),小米工厂只生产小米产品(小米手机 + 小米笔记本)。每个工厂生产的产品都是同一个品牌的"全家桶",产品之间可以完美协同工作。

核心概念

为什么需要抽象工厂?

在现实生活中,我们经常需要购买一整套相关的产品:

  • 🍎 苹果生态:iPhone + MacBook + AirPods(无缝协同)

  • 📱 小米生态:小米手机 + 小米笔记本 + 小米耳机(互联互通)

  • 🎮 游戏生态:PlayStation + 手柄 + 游戏光盘(完美适配)

如果你混搭不同品牌的产品,可能会遇到兼容性问题。抽象工厂模式就是为了解决这个问题。

产品族 vs 产品等级结构

  • 产品等级结构:同类产品的继承层次

    • 手机 → iPhone、小米手机、华为手机

    • 笔记本 → MacBook、小米笔记本、华为笔记本

  • 产品族:不同产品等级结构中相关的产品组合

    • 苹果产品族:iPhone + MacBook

    • 小米产品族:小米手机 + 小米笔记本

模式结构

抽象工厂模式包含以下几个角色:

  1. 抽象产品 (Abstract Product): 定义产品的接口(如Phone、Laptop)

  2. 具体产品 (Concrete Product): 实现抽象产品接口的具体类(如iPhone、MacBook)

  3. 抽象工厂 (Abstract Factory): 定义创建产品族的接口

  4. 具体工厂 (Concrete Factory): 实现抽象工厂,创建具体的产品族

  5. 客户端 (Client): 使用抽象工厂和抽象产品接口

与其他工厂模式的比较

特性简单工厂工厂方法抽象工厂
产品数量单一产品单一产品产品族
工厂数量一个多个多个
扩展方式修改工厂增加工厂增加工厂族
复杂度
使用场景产品少且固定产品种类需扩展产品族需整体切换

代码示例说明

1. 抽象产品接口

// 手机接口 - 抽象产品A
type Phone interface {
    Call(number string)
    GetModel() string
    GetBrand() string
    ShowSpecs()
}

// 笔记本电脑接口 - 抽象产品B  
type Laptop interface {
    PowerOn()
    GetModel() string
    GetBrand() string
    ConnectToPhone(phone Phone) string  // 关键:与手机协同工作
}

重点ConnectToPhone 方法体现了产品族内产品的相关性 - 同品牌设备连接更完美!

2. 苹果产品族实现

// 苹果手机 - 具体产品A1
type iPhone struct {
    model string
    brand string
}

func (p *iPhone) Call(number string) {
    fmt.Printf("📱 %s拨打电话到 %s (使用FaceTime音频)\n", p.model, number)
}

func (p *iPhone) ShowSpecs() {
    fmt.Printf("📱 %s规格: A17处理器, iOS系统, 支持5G\n", p.model)
}

// 苹果笔记本 - 具体产品B1
type MacBook struct {
    model string
    brand string
}

func (m *MacBook) ConnectToPhone(phone Phone) string {
    if phone.GetBrand() == m.brand {
        return fmt.Sprintf("🔗 %s与%s完美连接 - 支持连续互通、AirDrop、通用剪贴板", 
            m.model, phone.GetModel())
    }
    return fmt.Sprintf("⚠️ %s与%s连接受限 - 仅支持基础蓝牙功能", 
        m.model, phone.GetModel())
}

核心思想:同品牌产品有特殊的协同功能,跨品牌则功能受限。

3. 小米产品族实现

// 小米手机 - 具体产品A2
type XiaomiPhone struct {
    model string
    brand string
}

func (p *XiaomiPhone) Call(number string) {
    fmt.Printf("📱 %s拨打电话到 %s (使用小米通话)\n", p.model, number)
}

// 小米笔记本 - 具体产品B2
type XiaomiLaptop struct {
    model string
    brand string
}

func (m *XiaomiLaptop) ConnectToPhone(phone Phone) string {
    if phone.GetBrand() == m.brand {
        return fmt.Sprintf("🔗 %s与%s完美连接 - 支持小米互传、多屏协同、文件共享", 
            m.model, phone.GetModel())
    }
    return fmt.Sprintf("⚠️ %s与%s连接受限 - 仅支持基础蓝牙功能", 
        m.model, phone.GetModel())
}

4. 抽象工厂接口

// 电子设备工厂接口
type ElectronicsFactory interface {
    CreatePhone() Phone      // 创建手机
    CreateLaptop() Laptop    // 创建笔记本
    GetBrandName() string    // 获取品牌名
}

设计要点:一个工厂负责创建整个产品族,确保产品间的兼容性。

5. 具体工厂实现

// 苹果工厂 - 只生产苹果产品族
type AppleFactory struct{}

func (f *AppleFactory) CreatePhone() Phone {
    return &iPhone{
        model: "iPhone 15 Pro",
        brand: "Apple",
    }
}

func (f *AppleFactory) CreateLaptop() Laptop {
    return &MacBook{
        model: "MacBook Pro M3",
        brand: "Apple",
    }
}

// 小米工厂 - 只生产小米产品族
type XiaomiFactory struct{}

func (f *XiaomiFactory) CreatePhone() Phone {
    return &XiaomiPhone{
        model: "小米14 Pro",
        brand: "Xiaomi",
    }
}

func (f *XiaomiFactory) CreateLaptop() Laptop {
    return &XiaomiLaptop{
        model: "小米笔记本Pro",
        brand: "Xiaomi",
    }
}

6. 设备套装类

// 电子设备套装 - 体现产品族的完整性
type DeviceBundle struct {
    phone  Phone
    laptop Laptop
    brand  string
}

func NewDeviceBundle(factory ElectronicsFactory) *DeviceBundle {
    return &DeviceBundle{
        phone:  factory.CreatePhone(),     // 同一工厂创建
        laptop: factory.CreateLaptop(),    // 确保兼容性
        brand:  factory.GetBrandName(),
    }
}

func (db *DeviceBundle) ShowBundle() {
    fmt.Printf("\n📦 === %s全家桶套装 ===\n", db.brand)
    fmt.Printf("📱 手机: %s\n", db.phone.GetModel())
    fmt.Printf("💻 笔记本: %s\n", db.laptop.GetModel())

    // 展示生态协同优势
    connectionResult := db.laptop.ConnectToPhone(db.phone)
    fmt.Printf("🔗 生态协同: %s\n", connectionResult)
}

7. 客户端使用

func main() {
    // 创建不同品牌的工厂
    appleFactory := NewAppleFactory()
    xiaomiFactory := NewXiaomiFactory()

    // 创建品牌生态套装
    appleBundle := NewDeviceBundle(appleFactory)   // 苹果全家桶
    xiaomiBundle := NewDeviceBundle(xiaomiFactory) // 小米全家桶

    appleBundle.ShowBundle()
    xiaomiBundle.ShowBundle()

    // 演示跨品牌混搭的问题
    fmt.Println("\n⚠️ === 混搭不同品牌的问题演示 ===")
    applePhone := appleFactory.CreatePhone()
    xiaomiLaptop := xiaomiFactory.CreateLaptop()

    connectionResult := xiaomiLaptop.ConnectToPhone(applePhone)
    fmt.Printf("🔗 跨品牌连接: %s\n", connectionResult)
    fmt.Println("💡 这就是为什么我们需要抽象工厂来确保产品族的一致性!")
}

运行示例

运行 abstract_factory.go 文件:

go run abstract_factory.go

输出结果:

🎯 === 抽象工厂模式 - 电子设备品牌工厂 ===

🏭 === Apple设备使用演示 ===
📱 iPhone 15 Pro规格: A17处理器, iOS系统, 支持5G
📱 iPhone 15 Pro拨打电话到 13888888888 (使用FaceTime音频)
💻 MacBook Pro M3开机 (苹果开机音效)

🔄 设备协同测试:
🔗 MacBook Pro M3与iPhone 15 Pro完美连接 - 支持连续互通、AirDrop、通用剪贴板

🏭 === Xiaomi设备使用演示 ===
📱 小米14 Pro规格: 骁龙处理器, MIUI系统, 支持5G
📱 小米14 Pro拨打电话到 13888888888 (使用小米通话)
💻 小米笔记本Pro开机 (小米开机动画)

🔄 设备协同测试:
🔗 小米笔记本Pro与小米14 Pro完美连接 - 支持小米互传、多屏协同、文件共享

==================================================

📦 === Apple全家桶套装 ===
📱 手机: iPhone 15 Pro
💻 笔记本: MacBook Pro M3
🔗 生态协同: 🔗 MacBook Pro M3与iPhone 15 Pro完美连接 - 支持连续互通、AirDrop、通用剪贴板

📦 === Xiaomi全家桶套装 ===
📱 手机: 小米14 Pro
💻 笔记本: 小米笔记本Pro
🔗 生态协同: 🔗 小米笔记本Pro与小米14 Pro完美连接 - 支持小米互传、多屏协同、文件共享

==================================================

⚠️ === 混搭不同品牌的问题演示 ===
📱 设备: iPhone 15 Pro
💻 设备: 小米笔记本Pro
🔗 跨品牌连接: ⚠️ 小米笔记本Pro与iPhone 15 Pro连接受限 - 仅支持基础蓝牙功能
💡 这就是为什么我们需要抽象工厂来确保产品族的一致性!

优点

  1. 🔐 确保产品族的一致性:同一工厂创建的产品保证兼容

  2. 🔄 符合开闭原则:添加新品牌时无需修改现有代码

  3. 🎯 分离了具体类:客户端只依赖抽象接口

  4. ⚡ 易于切换产品族:只需更换工厂即可切换整个品牌生态

缺点

  1. 📈 增加了系统复杂性:需要定义大量的类和接口

  2. 🔧 扩展困难:添加新产品类型需要修改所有工厂接口

  3. 📊 类数量增加:每个产品族都需要相应的类

设计原则体现

  1. 🎯 依赖倒置原则:高层模块依赖抽象工厂接口

  2. 🔓 开闭原则:对扩展开放(新增品牌),对修改关闭

  3. 🔄 里氏替换原则:不同品牌工厂可以互相替换

  4. 📋 单一职责原则:每个工厂只负责一个品牌的产品族

与其他模式的区别

vs 建造者模式

特性抽象工厂模式建造者模式
目的创建产品族创建复杂对象
侧重点产品的组合产品的构造过程
产品关系相关产品族单一复杂产品

vs 工厂方法模式

特性抽象工厂模式工厂方法模式
产品数量多个相关产品单个产品
工厂职责创建产品族创建单一产品
扩展方式增加整个产品族增加单个产品类型

记忆口诀

"一个工厂一个牌,全家桶里不混搭"

  • 一个工厂 = 一个品牌

  • 全家桶 = 产品族(相关产品的组合)

  • 不混搭 = 确保产品族的一致性

总结

抽象工厂模式就像现实中的品牌专卖店:

  • 🍎 苹果店:只卖苹果产品,产品间无缝协同

  • 📱 小米店:只卖小米产品,生态互联互通

  • 🎮 索尼店:只卖索尼产品,完美适配

当你需要确保一套产品风格统一、功能协同时,抽象工厂模式是最佳选择。它虽然增加了代码复杂性,但换来了产品族的一致性和系统的可扩展性。

0
Subscribe to my newsletter

Read articles from shaojie li directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

shaojie li
shaojie li

Hi there 👋, I'm [mamba] I'm a Speech Recognition Engineer with a passion for machine learning and natural language processing. I love working on impactful projects and am always looking for new challenges.