设计模式 | 工厂模式
工厂模式(Factory Pattern) 是创建型设计模式的核心成员,它通过将对象创建的逻辑封装起来,实现了创建与使用的解耦。本文将深入探讨工厂模式的核心思想、实现技巧以及在C++中的高效实现方式。
为什么需要工厂模式?
在软件开发中,直接使用new
关键字创建对象会带来诸多问题:
-
紧耦合:客户端代码依赖具体类实现
-
难以扩展:添加新产品需要修改客户端代码
-
职责混乱:对象创建逻辑分散在各处
-
违反开闭原则:对修改开放,对扩展封闭
工厂模式通过封装对象创建过程解决了这些问题,提供了一种灵活的创建机制。当你的代码中存在以下情况时,工厂模式特别有用:
-
无法预知需要创建的具体类型
-
需要集中管理对象的创建逻辑
-
系统需要支持多种类型的产品
-
希望将实例化延迟到子类
工厂模式的两种形态
1. 简单工厂模式(静态工厂)
简单工厂模式是最基础的形式,它通过一个静态方法封装对象的创建逻辑。
#include <iostream>
#include <memory>
#include <stdexcept>// 抽象产品类:图形接口
class Shape {
public:virtual void draw() const = 0;virtual ~Shape() = default;
};// 具体产品类:圆形
class Circle : public Shape {
public:void draw() const override {std::cout << "○ 绘制圆形" << std::endl;}
};// 具体产品类:矩形
class Rectangle : public Shape {
public:void draw() const override {std::cout << "□ 绘制矩形" << std::endl;}
};// 具体产品类:三角形
class Triangle : public Shape {
public:void draw() const override {std::cout << "△ 绘制三角形" << std::endl;}
};// 简单工厂类
class ShapeFactory {
public:// 形状类型枚举enum ShapeType { CIRCLE, RECTANGLE, TRIANGLE };// 创建形状的静态方法static std::unique_ptr<Shape> createShape(ShapeType type) {switch (type) {case CIRCLE:return std::make_unique<Circle>();case RECTANGLE:return std::make_unique<Rectangle>();case TRIANGLE:return std::make_unique<Triangle>();default:throw std::invalid_argument("错误:不支持的形状类型");}}
};// 创建具体实列
int main() {// 创建圆形auto circle = ShapeFactory::createShape(ShapeFactory::CIRCLE);circle->draw();// 创建矩形auto rect = ShapeFactory::createShape(ShapeFactory::RECTANGLE);rect->draw();// 创建三角形auto triangle = ShapeFactory::createShape(ShapeFactory::TRIANGLE);triangle->draw();return 0;
}
优点:
-
实现简单,易于理解
-
集中管理对象的创建逻辑
-
客户端与具体产品类解耦
缺点:
-
违反开闭原则(添加新产品需修改工厂类)
-
工厂类职责过重(所有产品都在一个工厂中创建)
-
不支持运行时动态扩展
2. 工厂方法模式
工厂方法模式将对象创建延迟到子类,解决了简单工厂的开闭原则问题。
#include <iostream>
#include <memory>
#include <vector>// 抽象产品:日志记录器
class Logger {
public:virtual void log(const std::string& message) = 0;virtual ~Logger() = default;
};// 具体产品:文件日志
class FileLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[文件日志] " << message << std::endl;}
};// 具体产品:控制台日志
class ConsoleLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[控制台日志] " << message << std::endl;}
};// 具体产品:网络日志
class NetworkLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "[网络日志] " << message << std::endl;}
};// 抽象创建者
class LoggerCreator {
public:virtual std::unique_ptr<Logger> createLogger() = 0;void logMessage(const std::string& message) {auto logger = createLogger();logger->log(message);}virtual ~LoggerCreator() = default;
};// 具体创建者:文件日志工厂
class FileLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<FileLogger>();}
};// 具体创建者:控制台日志工厂
class ConsoleLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<ConsoleLogger>();}
};// 具体创建者:网络日志工厂
class NetworkLoggerCreator : public LoggerCreator {
public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<NetworkLogger>();}
};// 创建实例
int main() {std::vector<std::unique_ptr<LoggerCreator>> creators;creators.push_back(std::make_unique<FileLoggerCreator>());creators.push_back(std::make_unique<ConsoleLoggerCreator>());creators.push_back(std::make_unique<NetworkLoggerCreator>());for (auto& creator : creators) {creator->logMessage("应用启动完成");}return 0;
}
核心思想:
-
定义创建对象的接口,但让子类决定实例化哪个类
-
工厂方法使一个类的实例化延迟到其子类
-
符合"开闭原则" - 对扩展开放,对修改关闭
工厂方法模式的高级应用
1. 参数化工厂方法
class UniversalCreator : public LoggerCreator {
public:enum LoggerType { FILE, CONSOLE, NETWORK };UniversalCreator(LoggerType type) : type_(type) {}std::unique_ptr<Logger> createLogger() override {switch (type_) {case FILE: return std::make_unique<FileLogger>();case CONSOLE: return std::make_unique<ConsoleLogger>();case NETWORK: return std::make_unique<NetworkLogger>();default: throw std::invalid_argument("无效的日志类型");}}private:LoggerType type_;
};// 使用示例
int main() {UniversalCreator fileCreator(UniversalCreator::FILE);fileCreator.logMessage("保存到文件");UniversalCreator consoleCreator(UniversalCreator::CONSOLE);consoleCreator.logMessage("输出到控制台");return 0;
}
2. 工厂方法 + 单例模式
class Database {
public:virtual void connect() = 0;virtual ~Database() = default;
};class MySQL : public Database {
public:void connect() override {std::cout << "连接到MySQL数据库" << std::endl;}static MySQL& getInstance() {static MySQL instance;return instance;}private:MySQL() = default;
};class PostgreSQL : public Database {
public:void connect() override {std::cout << "连接到PostgreSQL数据库" << std::endl;}static PostgreSQL& getInstance() {static PostgreSQL instance;return instance;}private:PostgreSQL() = default;
};class DatabaseFactory {
public:virtual Database& create() = 0;virtual ~DatabaseFactory() = default;
};class MySQLFactory : public DatabaseFactory {
public:Database& create() override {return MySQL::getInstance();}
};class PostgreSQLFactory : public DatabaseFactory {
public:Database& create() override {return PostgreSQL::getInstance();}
};// 使用示例
int main() {MySQLFactory mysqlFactory;auto& mysql = mysqlFactory.create();mysql.connect();PostgreSQLFactory pgFactory;auto& pg = pgFactory.create();pg.connect();return 0;
}
工厂模式的优缺点分析
优点:
-
解耦创建者和具体产品
-
符合开闭原则,易于扩展
-
单一职责原则(创建逻辑集中)
-
便于代码维护和测试
-
支持依赖倒置原则
缺点:
-
引入额外类,增加系统复杂性
-
需要设计良好的继承体系
-
客户端可能需要理解工厂结构
-
简单场景下可能显得过度设计
工厂模式的典型应用场景
-
框架设计:框架需要为应用提供扩展点
class Plugin { public:virtual void execute() = 0;virtual ~Plugin() = default; };class PluginFactory { public:virtual std::unique_ptr<Plugin> createPlugin() = 0; };
-
跨平台开发:为不同平台创建适配对象
class GUIButton { public:virtual void render() = 0; };class WindowsButton : public GUIButton { /*...*/ }; class MacButton : public GUIButton { /*...*/ };class GUIFactory { public:virtual std::unique_ptr<GUIButton> createButton() = 0; };
-
对象池管理:管理可重用对象的创建
class Connection { public:virtual void open() = 0; };class ConnectionPool { public:virtual std::unique_ptr<Connection> createConnection() = 0;virtual void returnConnection(std::unique_ptr<Connection>) = 0; };
-
依赖注入:通过工厂注入依赖对象
class Service { public:virtual void performTask() = 0; };class Client { public:Client(std::unique_ptr<ServiceFactory> factory): factory_(std::move(factory)) {}void execute() {auto service = factory_->createService();service->performTask();}private:std::unique_ptr<ServiceFactory> factory_; };
工厂模式的最佳实践
-
优先使用工厂方法:除非系统非常简单,否则优先选择工厂方法模式
-
结合智能指针:使用
std::unique_ptr
或std::shared_ptr
管理对象生命周期 -
使用模板减少重复代码
template <typename T> class StandardCreator : public LoggerCreator { public:std::unique_ptr<Logger> createLogger() override {return std::make_unique<T>();} };// 使用 StandardCreator<FileLogger> fileCreator;
-
工厂方法命名规范:
-
createXXX()
-
makeXXX()
-
newXXX()
-
getInstance()
(单例场景)
工厂模式 vs 简单工厂
特性 | 简单工厂模式 | 工厂方法模式 |
---|---|---|
开闭原则 | 违反(修改工厂类) | 支持(扩展子类) |
复杂度 | 简单 | 中等 |
扩展性 | 有限 | 优秀 |
类数量 | 较少 | 较多(每个产品对应工厂) |
适用场景 | 产品类型少且固定 | 产品类型多或可能扩展 |
总结
工厂模式是C++开发中强大的对象创建工具,通过封装对象的创建过程,它实现了:
-
解耦:客户端代码与具体类实现分离
-
扩展性:轻松添加新产品而不影响现有代码
-
可维护性:集中管理创建逻辑
-
灵活性:支持运行时决策和配置
在实际开发中,应当根据具体需求选择合适的工厂模式变体:
-
对于简单场景,简单工厂足够高效
-
对于需要高度扩展的系统,工厂方法是最佳选择
-
避免过早优化,但为未来扩展留有余地
"设计模式不是银弹,而是工具箱中的工具。工厂模式是其中最常用且强大的工具之一。" - 设计模式实践者