1 核心定义
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪个类。工厂方法让类的实例化推迟到子类进行,实现了"对象创建"与"对象使用"的分离。
2 核心思想
1 封装对象创建:将对象的创建过程封装在工厂方法中
2 延迟实例化:将具体类的实例化延迟到子类
3 依赖倒置:依赖抽象工厂,而不是具体类
4 可扩展性:新增产品时,只需扩展工厂,无需修改客户端代码
3 结构组成
Product(产品接口):定义产品的接口
ConcreteProduct(具体产品):实现产品接口的具体类
Creator(创建者抽象类):声明工厂方法,返回Product对象
ConcreteCreator(具体创建者):重写工厂方法,返回具体产品
4 应用场景举例
以日志记录器系统为例:
1 多种日志记录方式:文件日志、数据库日志、控制台日志
2 每种日志记录方式有不同的初始化方式和配置要求
3 客户端需要根据配置或条件选择不同的日志记录器
4 日志记录器的创建过程可能很复杂,包括配置加载、连接建立等
5 UML

6 c++ 代码实现
cpp
#include <iostream>
#include <string>
#include <memory>
#include <fstream>
#include <ctime>
using namespace std;
// 产品接口:日志记录器
class Logger {
public:
virtual ~Logger() = default;
virtual void log(const string& message) = 0;
virtual void error(const string& message) = 0;
virtual void warn(const string& message) = 0;
};
// 具体产品:文件日志记录器
class FileLogger : public Logger {
private:
string filename;
ofstream logFile;
string getCurrentTime() {
time_t now = time(nullptr);
return ctime(&now);
}
public:
FileLogger(const string& file) : filename(file) {
logFile.open(filename, ios::app);
if (!logFile.is_open()) {
throw runtime_error("无法打开日志文件: " + filename);
}
log("【文件日志系统启动】");
}
~FileLogger() {
if (logFile.is_open()) {
log("【文件日志系统关闭】");
logFile.close();
}
}
void log(const string& message) override {
logFile << "[INFO][" << getCurrentTime() << "] " << message << endl;
logFile.flush();
}
void error(const string& message) override {
logFile << "[ERROR][" << getCurrentTime() << "] " << message << endl;
logFile.flush();
}
void warn(const string& message) override {
logFile << "[WARN][" << getCurrentTime() << "] " << message << endl;
logFile.flush();
}
};
// 具体产品:数据库日志记录器
class DatabaseLogger : public Logger {
private:
string connectionString;
void connectToDatabase() {
cout << "连接到数据库: " << connectionString << endl;
// 模拟数据库连接
}
void disconnectFromDatabase() {
cout << "断开数据库连接" << endl;
}
public:
DatabaseLogger(const string& connStr) : connectionString(connStr) {
connectToDatabase();
log("【数据库日志系统启动】");
}
~DatabaseLogger() {
log("【数据库日志系统关闭】");
disconnectFromDatabase();
}
void log(const string& message) override {
cout << "[数据库日志] " << message << endl;
// 实际项目这里会执行SQL插入操作
}
void error(const string& message) override {
cout << "[数据库日志][ERROR] " << message << endl;
}
void warn(const string& message) override {
cout << "[数据库日志][WARN] " << message << endl;
}
};
// 具体产品:控制台日志记录器
class ConsoleLogger : public Logger {
private:
bool colorEnabled;
void setConsoleColor(const string& color) {
// 设置控制台颜色的代码
if (color == "red") cout << "\033[31m";
else if (color == "yellow") cout << "\033[33m";
else if (color == "green") cout << "\033[32m";
}
void resetConsoleColor() {
cout << "\033[0m";
}
public:
ConsoleLogger(bool enableColor = true) : colorEnabled(enableColor) {
cout << "控制台日志系统启动" << endl;
}
void log(const string& message) override {
if (colorEnabled) setConsoleColor("green");
cout << "[INFO] " << message << endl;
if (colorEnabled) resetConsoleColor();
}
void error(const string& message) override {
if (colorEnabled) setConsoleColor("red");
cerr << "[ERROR] " << message << endl;
if (colorEnabled) resetConsoleColor();
}
void warn(const string& message) override {
if (colorEnabled) setConsoleColor("yellow");
cout << "[WARN] " << message << endl;
if (colorEnabled) resetConsoleColor();
}
};
// 抽象创建者:日志记录器工厂
class LoggerFactory {
public:
virtual ~LoggerFactory() = default;
// 工厂方法
virtual Logger* createLogger() = 0;
// 可以在工厂中添加一些公共的创建后处理逻辑
Logger* getLogger() {
Logger* logger = createLogger();
// 可以在这里添加一些通用的初始化代码
cout << "日志记录器创建成功" << endl;
return logger;
}
};
// 具体创建者:文件日志记录器工厂
class FileLoggerFactory : public LoggerFactory {
private:
string filename;
public:
FileLoggerFactory(const string& file) : filename(file) {}
Logger* createLogger() override {
return new FileLogger(filename);
}
};
// 具体创建者:数据库日志记录器工厂
class DatabaseLoggerFactory : public LoggerFactory {
private:
string connectionString;
public:
DatabaseLoggerFactory(const string& connStr) : connectionString(connStr) {}
Logger* createLogger() override {
return new DatabaseLogger(connectionString);
}
};
// 具体创建者:控制台日志记录器工厂
class ConsoleLoggerFactory : public LoggerFactory {
private:
bool colorEnabled;
public:
ConsoleLoggerFactory(bool enableColor = true) : colorEnabled(enableColor) {}
Logger* createLogger() override {
return new ConsoleLogger(colorEnabled);
}
};
// 客户端代码
class Application {
private:
unique_ptr<Logger> logger;
public:
void initialize(const string& logType) {
LoggerFactory* factory = nullptr;
// 根据配置选择具体的工厂
if (logType == "file") {
factory = new FileLoggerFactory("app.log");
} else if (logType == "database") {
factory = new DatabaseLoggerFactory("localhost:3306/logdb");
} else if (logType == "console") {
factory = new ConsoleLoggerFactory(true);
} else {
throw runtime_error("不支持的日志类型");
}
// 通过工厂创建日志记录器
logger.reset(factory->getLogger());
delete factory;
}
void run() {
if (!logger) {
cout << "日志系统未初始化" << endl;
return;
}
logger->log("应用程序启动");
logger->warn("这是一个警告信息");
logger->error("这是一个错误信息");
logger->log("应用程序运行中...");
}
};
// 主函数
int main() {
try {
cout << "=== 使用文件日志 ===" << endl;
Application app1;
app1.initialize("file");
app1.run();
cout << endl;
cout << "=== 使用数据库日志 ===" << endl;
Application app2;
app2.initialize("database");
app2.run();
cout << endl;
cout << "=== 使用控制台日志 ===" << endl;
Application app3;
app3.initialize("console");
app3.run();
} catch (const exception& e) {
cerr << "错误: " << e.what() << endl;
}
return 0;
}
7 对比分析与优势总结
7.1 不使用工厂方法模式的坏处
不使用工厂方法模式的坏处
如果不使用工厂方法模式,可能会采用以下几种实现方式:
方式1:直接使用new创建对象
cpp
class Application {
private:
Logger* logger;
public:
void initialize(const string& logType) {
// 直接在客户端代码中创建具体对象
if (logType == "file") {
logger = new FileLogger("app.log");
} else if (logType == "database") {
logger = new DatabaseLogger("localhost:3306/logdb");
} else if (logType == "console") {
logger = new ConsoleLogger(true);
}
}
// ... 其他代码
};
问题:
客户端代码与具体产品类耦合
创建逻辑分散在各个客户端中
添加新的日志类型需要修改所有客户端代码
方式2:使用简单工厂
cpp
class SimpleLoggerFactory {
public:
static Logger* createLogger(const string& type) {
if (type == "file") {
return new FileLogger("app.log");
} else if (type == "database") {
return new DatabaseLogger("localhost:3306/logdb");
} else if (type == "console") {
return new ConsoleLogger(true);
}
return nullptr;
}
};
问题:
工厂类职责过重,包含所有产品的创建逻辑
添加新产品需要修改工厂类,违反开闭原则
无法通过继承来改变创建行为
方式3:使用全局函数或宏
cpp
#define CREATE_FILE_LOGGER() new FileLogger("app.log")
#define CREATE_DATABASE_LOGGER() new DatabaseLogger("localhost:3306/logdb")
问题:
缺乏类型安全
调试困难
无法进行面向对象扩展
7.2 使用工厂方法模式的优势
1 解耦:客户端代码与具体产品类解耦
2 可扩展:添加新产品时无需修改现有代码
3 统一创建接口:所有产品都通过统一的工厂方法创建
4 支持复杂创建过程:可以在工厂方法中封装复杂的创建逻辑
5 符合单一职责:创建对象的职责被集中到工厂类中
6 便于测试:可以创建测试专用的工厂类返回mock对象
8 适用场景
客户端不知道它所需要的对象的具体类
工厂类希望由子类指定创建的对象类型
对象的创建过程比较复杂,需要独立封装
需要在不同条件下创建不同的产品实例
需要将对象的创建和使用分离
工厂方法模式通过将对象的创建延迟到子类,很好地解决了对象创建过程中的耦合问题,是创建型设计模式中非常重要的一种。