1. 概述

GoF分类

工厂方法模式属于创建型设计模式

官方定义

定义一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

核心目的

解决对象创建过程中的灵活性问题,避免在代码中直接使用new运算符,将对象创建与使用解耦。

主要问题

当系统需要处理多种类型的对象创建,且这些对象的创建逻辑可能变化时,直接使用具体类名会导致:

  1. 违反开闭原则(对扩展开放,对修改关闭)

  2. 代码耦合度高

  3. 难以进行单元测试

C++应用价值

  • Qt框架中的QObject创建机制

  • 游戏开发中不同角色/武器的创建

  • 跨平台UI组件实例化

关键特征

  1. 将对象创建封装在单独方法中

  2. 通过继承实现多态创建

  3. 客户端代码仅依赖抽象接口

  4. 符合依赖倒置原则

2. 核心思想

设计哲学

“不要调用我,我会调用你”(Hollywood Principle)——将创建逻辑下放到子类实现

面向对象原则

  1. 开闭原则​:通过继承扩展新类型,无需修改现有代码

  2. 单一职责​:创建逻辑集中在工厂类中

  3. 依赖倒置​:客户端依赖抽象而非具体类

C++特殊考虑

  1. 使用智能指针管理对象生命周期

  2. 工厂方法通常返回unique_ptrshared_ptr

  3. 考虑模板化工厂提高复用性

工作流程

ClientCreatorConcreteCreatorConcreteProductfactoryMethod()createProduct()new()return Productreturn ProductClientCreatorConcreteCreatorConcreteProduct

3. 适用场景

适用场景

  1. 跨平台UI组件创建
// 抽象按钮工厂
class ButtonFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
};

// Windows按钮实现
class WindowsButtonFactory : public ButtonFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
};
  1. 游戏角色生成系统
class CharacterSpawner {
public:
    virtual std::shared_ptr<Character> spawn() = 0;
};

class MonsterSpawner : public CharacterSpawner {
public:
    std::shared_ptr<Character> spawn() override {
        return std::make_shared<Monster>();
    }
};
  1. 数据库连接池管理
class ConnectionFactory {
public:
    virtual std::unique_ptr<DbConnection> createConnection() = 0;
};

不适用场景

  1. 简单对象创建​:如果对象创建逻辑永远不会变化,直接使用构造函数更简单

  2. 性能关键路径​:虚函数调用带来额外开销

  3. 对象数量极少​:模式带来的复杂性超过收益

替代方案:

  • 对于简单场景使用直接实例化

  • 性能敏感场景考虑对象池或原型模式

4. UML类图

creates
«interface»
Product
+operation()
ConcreteProductA
+operation()
ConcreteProductB
+operation()
«abstract»
Creator
+factoryMethod() : Product
+someOperation()
ConcreteCreatorA
+factoryMethod() : Product
ConcreteCreatorB
+factoryMethod() : Product

5. 结构

参与者分析

  1. Product(抽象产品)​
  • 定义工厂方法创建的对象的接口

  • 在C++中通常为抽象类或纯虚接口

  1. ConcreteProduct(具体产品)​
  • 实现Product接口的具体类

  • 每个具体产品对应一个具体工厂

  1. Creator(创建者)​
  • 声明工厂方法,返回Product类型对象

  • 可能包含依赖于Product的核心业务逻辑

  1. ConcreteCreator(具体创建者)​
  • 重写工厂方法返回具体ConcreteProduct实例

  • 负责实际的对象创建逻辑

协作流程

  1. 客户端调用ConcreteCreator的工厂方法

  2. ConcreteCreator实例化对应的ConcreteProduct

  3. 工厂方法返回Product指针/智能指针

  4. 客户端通过Product接口使用对象

6. 代码示例

// product.h
#pragma once
#include <memory>
#include <iostream>

// 抽象产品接口
class Document {
public:
    virtual ~Document() = default;
    virtual void open() = 0;
    virtual void save() = 0;
};

// 具体产品1
class TextDocument : public Document {
public:
    void open() override {
        std::cout << "Opening text document\n";
    }
    
    void save() override {
        std::cout << "Saving text document\n";
    }
};

// 具体产品2
class SpreadsheetDocument : public Document {
public:
    void open() override {
        std::cout << "Opening spreadsheet\n";
    }
    
    void save() override {
        std::cout << "Saving spreadsheet\n";
    }
};

// creator.h
class DocumentCreator {
public:
    virtual ~DocumentCreator() = default;
    
    // 工厂方法
    virtual std::unique_ptr<Document> createDocument() = 0;
    
    // 业务逻辑
    void newDocument() {
        auto doc = createDocument();
        doc->open();
    }
};

// 具体创建者1
class TextDocumentCreator : public DocumentCreator {
public:
    std::unique_ptr<Document> createDocument() override {
        return std::make_unique<TextDocument>();
    }
};

// 具体创建者2
class SpreadsheetCreator : public DocumentCreator {
public:
    std::unique_ptr<Document> createDocument() override {
        return std::make_unique<SpreadsheetDocument>();
    }
};

// main.cpp
#include "product.h"
#include "creator.h"

void clientCode(DocumentCreator& creator) {
    std::cout << "Client: Creating document\n";
    creator.newDocument();
}

int main() {
    std::cout << "App: Launched with TextDocument\n";
    TextDocumentCreator textCreator;
    clientCode(textCreator);
    
    std::cout << "\nApp: Launched with Spreadsheet\n";
    SpreadsheetCreator spreadsheetCreator;
    clientCode(spreadsheetCreator);
}

7. 运行结果

App: Launched with TextDocument
Client: Creating document
Opening text document

App: Launched with Spreadsheet
Client: Creating document
Opening spreadsheet

输出验证:

  1. 正确创建了不同类型的文档对象

  2. 客户端代码无需知道具体文档类型

  3. 工厂方法按预期返回了适当的产品

8. 应用场景

实际案例

  1. C++标准库​:std::make_uniquestd::make_shared本质上是工厂方法

  2. Qt框架​:QObject的创建机制

  3. 游戏引擎​:Unity的Prefab实例化系统

  4. 数据库驱动​:ODBC/JDBC连接工厂

行业应用

  1. 嵌入式系统​:设备驱动工厂

  2. 图形编程​:不同渲染器后端的创建

  3. 网络编程​:协议处理器工厂

9. 变体

主要变体

  1. 简单工厂​(非GoF标准)
class DocumentFactory {
public:
    enum class Type { Text, Spreadsheet };
    
    static std::unique_ptr<Document> create(Type type) {
        switch(type) {
            case Type::Text: return std::make_unique<TextDocument>();
            case Type::Spreadsheet: return std::make_unique<SpreadsheetDocument>();
            default: throw std::invalid_argument("Unknown document type");
        }
    }
};
  1. 模板工厂
template <typename T>
class GenericCreator {
public:
    std::unique_ptr<T> create() {
        return std::make_unique<T>();
    }
};

变体对比

变体优点缺点适用场景
经典工厂方法符合OCP,扩展性好类数量多需要灵活扩展的系统
简单工厂实现简单违反OCP类型固定的简单系统
模板工厂编译时多态,高性能灵活性较低性能关键路径

10. 工厂方法 vs. 其他模式

与抽象工厂区别

  • 工厂方法:创建单一产品,通过继承实现

  • 抽象工厂:创建产品族,通过组合实现

与建造者模式区别

  • 工厂方法:一次性创建完整对象

  • 建造者:分步骤构建复杂对象

选择指南

  • 当需要创建单一类型对象时使用工厂方法

  • 当需要创建相关对象族时使用抽象工厂

  • 当对象构建过程复杂时使用建造者

11. 优缺点分析

优点

  1. 松耦合
  • 客户端代码只依赖抽象接口

  • 符合依赖倒置原则

  • 易于单元测试(可mock工厂)

  1. 可扩展性
  • 添加新产品只需新增子类

  • 不修改已有代码

  • 符合开闭原则

缺点

  1. 类数量膨胀
  • 每个产品对应一个工厂类

  • 可能造成类数量过多

  1. 间接性
  • 增加了代码理解难度

  • 需要跟踪多个类之间的关系

12. 何时不要使用

反对信号

  1. 对象创建逻辑简单且稳定
  • 直接使用构造函数更清晰

  • 示例:简单的值对象创建

  1. 性能关键路径
  • 虚函数调用有额外开销

  • 考虑使用对象池或缓存

  1. 运行时类型已知
  • 如果类型在编译时即可确定

  • 使用模板可能更合适

13. 总结

核心价值

  • 将对象创建与使用解耦

  • 提高代码的可测试性和可维护性

  • 支持面向接口编程

最佳实践

  1. 优先返回unique_ptr而非裸指针

  2. 考虑将工厂方法设为静态

  3. 为工厂添加异常安全保证

进阶学习

  1. 研究抽象工厂模式

  2. 学习依赖注入框架

  3. 探索模板元编程实现编译时工厂

完整项目示例

# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(FactoryPattern)

set(CMAKE_CXX_STANDARD 17)

add_executable(factory_pattern
    src/product.h
    src/creator.h
    src/main.cpp
)

这个工厂方法模式的完整实现展示了如何在现代C++中应用这一经典设计模式,涵盖了从理论到实践的各个方面,包括最佳实践、变体分析和实际应用场景。

更多推荐