C++ · 设计模式 (对象创建= Factory Method<工厂模式>)
1. 概述
GoF分类
工厂方法模式属于创建型设计模式
官方定义
定义一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
核心目的
解决对象创建过程中的灵活性问题,避免在代码中直接使用new运算符,将对象创建与使用解耦。
主要问题
当系统需要处理多种类型的对象创建,且这些对象的创建逻辑可能变化时,直接使用具体类名会导致:
-
违反开闭原则(对扩展开放,对修改关闭)
-
代码耦合度高
-
难以进行单元测试
C++应用价值
-
Qt框架中的
QObject创建机制 -
游戏开发中不同角色/武器的创建
-
跨平台UI组件实例化
关键特征
-
将对象创建封装在单独方法中
-
通过继承实现多态创建
-
客户端代码仅依赖抽象接口
-
符合依赖倒置原则
2. 核心思想
设计哲学
“不要调用我,我会调用你”(Hollywood Principle)——将创建逻辑下放到子类实现
面向对象原则
-
开闭原则:通过继承扩展新类型,无需修改现有代码
-
单一职责:创建逻辑集中在工厂类中
-
依赖倒置:客户端依赖抽象而非具体类
C++特殊考虑
-
使用智能指针管理对象生命周期
-
工厂方法通常返回
unique_ptr或shared_ptr -
考虑模板化工厂提高复用性
工作流程
3. 适用场景
适用场景
- 跨平台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>();
}
};
- 游戏角色生成系统
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>();
}
};
- 数据库连接池管理
class ConnectionFactory {
public:
virtual std::unique_ptr<DbConnection> createConnection() = 0;
};
不适用场景
-
简单对象创建:如果对象创建逻辑永远不会变化,直接使用构造函数更简单
-
性能关键路径:虚函数调用带来额外开销
-
对象数量极少:模式带来的复杂性超过收益
替代方案:
-
对于简单场景使用直接实例化
-
性能敏感场景考虑对象池或原型模式
4. UML类图
5. 结构
参与者分析
- Product(抽象产品)
-
定义工厂方法创建的对象的接口
-
在C++中通常为抽象类或纯虚接口
- ConcreteProduct(具体产品)
-
实现Product接口的具体类
-
每个具体产品对应一个具体工厂
- Creator(创建者)
-
声明工厂方法,返回Product类型对象
-
可能包含依赖于Product的核心业务逻辑
- ConcreteCreator(具体创建者)
-
重写工厂方法返回具体ConcreteProduct实例
-
负责实际的对象创建逻辑
协作流程
-
客户端调用ConcreteCreator的工厂方法
-
ConcreteCreator实例化对应的ConcreteProduct
-
工厂方法返回Product指针/智能指针
-
客户端通过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
输出验证:
-
正确创建了不同类型的文档对象
-
客户端代码无需知道具体文档类型
-
工厂方法按预期返回了适当的产品
8. 应用场景
实际案例
-
C++标准库:
std::make_unique和std::make_shared本质上是工厂方法 -
Qt框架:
QObject的创建机制 -
游戏引擎:Unity的Prefab实例化系统
-
数据库驱动:ODBC/JDBC连接工厂
行业应用
-
嵌入式系统:设备驱动工厂
-
图形编程:不同渲染器后端的创建
-
网络编程:协议处理器工厂
9. 变体
主要变体
- 简单工厂(非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");
}
}
};
- 模板工厂
template <typename T>
class GenericCreator {
public:
std::unique_ptr<T> create() {
return std::make_unique<T>();
}
};
变体对比
| 变体 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 经典工厂方法 | 符合OCP,扩展性好 | 类数量多 | 需要灵活扩展的系统 |
| 简单工厂 | 实现简单 | 违反OCP | 类型固定的简单系统 |
| 模板工厂 | 编译时多态,高性能 | 灵活性较低 | 性能关键路径 |
10. 工厂方法 vs. 其他模式
与抽象工厂区别
-
工厂方法:创建单一产品,通过继承实现
-
抽象工厂:创建产品族,通过组合实现
与建造者模式区别
-
工厂方法:一次性创建完整对象
-
建造者:分步骤构建复杂对象
选择指南
-
当需要创建单一类型对象时使用工厂方法
-
当需要创建相关对象族时使用抽象工厂
-
当对象构建过程复杂时使用建造者
11. 优缺点分析
优点
- 松耦合
-
客户端代码只依赖抽象接口
-
符合依赖倒置原则
-
易于单元测试(可mock工厂)
- 可扩展性
-
添加新产品只需新增子类
-
不修改已有代码
-
符合开闭原则
缺点
- 类数量膨胀
-
每个产品对应一个工厂类
-
可能造成类数量过多
- 间接性
-
增加了代码理解难度
-
需要跟踪多个类之间的关系
12. 何时不要使用
反对信号
- 对象创建逻辑简单且稳定
-
直接使用构造函数更清晰
-
示例:简单的值对象创建
- 性能关键路径
-
虚函数调用有额外开销
-
考虑使用对象池或缓存
- 运行时类型已知
-
如果类型在编译时即可确定
-
使用模板可能更合适
13. 总结
核心价值
-
将对象创建与使用解耦
-
提高代码的可测试性和可维护性
-
支持面向接口编程
最佳实践
-
优先返回
unique_ptr而非裸指针 -
考虑将工厂方法设为静态
-
为工厂添加异常安全保证
进阶学习
-
研究抽象工厂模式
-
学习依赖注入框架
-
探索模板元编程实现编译时工厂
完整项目示例
# 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++中应用这一经典设计模式,涵盖了从理论到实践的各个方面,包括最佳实践、变体分析和实际应用场景。
更多推荐



所有评论(0)