工厂方法模式 (Factory Method Pattern)

概述
工厂方法模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪个类。工厂方法将对象的创建推迟到子类中进行,从而使得系统在不修改具体工厂类的情况下引进新的产品。
模式结构
工厂方法模式包含以下几个角色:
产品接口 (Product Interface): 定义了产品的公共接口
具体产品 (Concrete Product): 实现产品接口的具体类
工厂接口 (Factory Interface): 声明了工厂方法,返回一个产品对象
具体工厂 (Concrete Factory): 实现工厂接口,负责创建具体产品
客户端 (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)
}
}
展示了如何使用不同的工厂创建不同的产品,以及工厂的多态性使用。
优点
符合开闭原则: 添加新产品时,只需要添加新的具体工厂,无需修改现有代码
符合单一职责原则: 每个工厂只负责创建一种产品
松耦合: 客户端代码与具体产品类解耦
多态性: 可以通过工厂接口统一处理不同类型的工厂
缺点
增加了系统复杂性: 每增加一个产品就需要增加一个具体工厂类
类的个数增加: 系统中类的个数成对增加
抽象层增加: 增加了系统的抽象性和理解难度
使用场景
创建对象的类型需要在运行时决定
系统需要在不修改现有代码的情况下添加新产品
产品的创建过程比较复杂,需要封装
希望将产品的创建和使用分离
实际应用示例
在实际开发中,工厂方法模式常用于:
日志记录器: 不同的日志工厂创建不同类型的日志记录器(文件日志、数据库日志、控制台日志)
数据库连接: 不同的数据库工厂创建不同类型的数据库连接
UI组件: 不同平台的工厂创建对应平台的UI组件
总结
工厂方法模式通过将产品的创建延迟到子类中进行,实现了创建和使用的分离,提高了系统的灵活性和可扩展性。虽然增加了系统的复杂性,但在需要频繁添加新产品类型的场景中,这种模式的优势非常明显。它是许多框架和库中常用的设计模式之一。
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.