工厂方法模式 (Factory Method Pattern)

shaojie lishaojie li
2 min read

概述

工厂方法模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪个类。工厂方法将对象的创建推迟到子类中进行,从而使得系统在不修改具体工厂类的情况下引进新的产品。

模式结构

工厂方法模式包含以下几个角色:

  1. 产品接口 (Product Interface): 定义了产品的公共接口

  2. 具体产品 (Concrete Product): 实现产品接口的具体类

  3. 工厂接口 (Factory Interface): 声明了工厂方法,返回一个产品对象

  4. 具体工厂 (Concrete Factory): 实现工厂接口,负责创建具体产品

  5. 客户端 (Client): 使用工厂接口创建产品的代码

与简单工厂模式的区别

特性简单工厂模式工厂方法模式
工厂数量一个工厂类多个工厂类
扩展性违反开闭原则符合开闭原则
产品创建通过参数决定通过不同工厂决定
复杂度简单相对复杂

代码示例说明

1. 产品接口 (Product Interface)

type Product interface {
    GetName() string
    GetDescription() string
    Use()
}

定义了所有产品都必须实现的方法,包括获取名称、描述和使用产品的功能。

2. 具体产品 (Concrete Products)

// ConcreteProductA is a concrete implementation of Product
type ConcreteProductA struct {
    name        string
    description string
}

func (p *ConcreteProductA) GetName() string {
    return p.name
}

func (p *ConcreteProductA) GetDescription() string {
    return p.description
}

func (p *ConcreteProductA) Use() {
    fmt.Printf("[Product A] Using %s: %s\n", p.name, p.description)
}

每个具体产品都实现了 Product 接口,并提供自己特有的实现逻辑。

3. 工厂接口 (Factory Interface)

// Factory interface defines the factory method that subclasses must implement
type Factory interface {
    CreateProduct() Product
    GetFactoryType() string
}

工厂接口定义了创建产品的方法,这是工厂方法模式的核心。每个具体工厂都必须实现这个接口。

4. 具体工厂 (Concrete Factories)

// ConcreteFactoryA creates ConcreteProductA
type ConcreteFactoryA struct {
    factoryType string
}

func NewConcreteFactoryA() *ConcreteFactoryA {
    return &ConcreteFactoryA{
        factoryType: "Factory A",
    }
}

func (f *ConcreteFactoryA) CreateProduct() Product {
    return &ConcreteProductA{
        name:        "High-Performance Laptop",
        description: "A powerful laptop for professional work",
    }
}

func (f *ConcreteFactoryA) GetFactoryType() string {
    return f.factoryType
}

每个具体工厂负责创建特定类型的产品。这样,当需要添加新产品时,只需要添加新的具体工厂,而不需要修改现有代码。

5. 客户端代码 (Client Code)

// Client code that uses the factory method
func ClientCode(factory Factory) {
    fmt.Printf("Client: Working with %s\n", factory.GetFactoryType())
    product := factory.CreateProduct()
    product.Use()
    fmt.Printf("Product Name: %s\n", product.GetName())
    fmt.Printf("Product Description: %s\n\n", product.GetDescription())
}

客户端代码通过工厂接口来创建产品,不需要知道具体的产品类型,实现了松耦合。

6. 主函数示例

func main() {
    fmt.Println("=== Factory Method Pattern Demo ===\n")

    // Using ConcreteFactoryA
    factoryA := NewConcreteFactoryA()
    ClientCode(factoryA)

    // Using ConcreteFactoryB
    factoryB := NewConcreteFactoryB()
    ClientCode(factoryB)

    // Demonstrating polymorphism
    fmt.Println("=== Demonstrating Factory Polymorphism ===")
    factories := []Factory{
        NewConcreteFactoryA(),
        NewConcreteFactoryB(),
    }

    for i, factory := range factories {
        fmt.Printf("Factory %d:\n", i+1)
        ClientCode(factory)
    }
}

展示了如何使用不同的工厂创建不同的产品,以及工厂的多态性使用。

优点

  1. 符合开闭原则: 添加新产品时,只需要添加新的具体工厂,无需修改现有代码

  2. 符合单一职责原则: 每个工厂只负责创建一种产品

  3. 松耦合: 客户端代码与具体产品类解耦

  4. 多态性: 可以通过工厂接口统一处理不同类型的工厂

缺点

  1. 增加了系统复杂性: 每增加一个产品就需要增加一个具体工厂类

  2. 类的个数增加: 系统中类的个数成对增加

  3. 抽象层增加: 增加了系统的抽象性和理解难度

使用场景

  1. 创建对象的类型需要在运行时决定

  2. 系统需要在不修改现有代码的情况下添加新产品

  3. 产品的创建过程比较复杂,需要封装

  4. 希望将产品的创建和使用分离

实际应用示例

在实际开发中,工厂方法模式常用于:

  • 日志记录器: 不同的日志工厂创建不同类型的日志记录器(文件日志、数据库日志、控制台日志)

  • 数据库连接: 不同的数据库工厂创建不同类型的数据库连接

  • UI组件: 不同平台的工厂创建对应平台的UI组件

总结

工厂方法模式通过将产品的创建延迟到子类中进行,实现了创建和使用的分离,提高了系统的灵活性和可扩展性。虽然增加了系统的复杂性,但在需要频繁添加新产品类型的场景中,这种模式的优势非常明显。它是许多框架和库中常用的设计模式之一。

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.