继 Day 1 学习了单例模式之后,今天我们继续深入对象创建型设计模式------工厂方法模式(Factory Method)。工厂方法模式为对象创建提供了更大的灵活性和扩展性,是实际开发中使用频率极高的一种设计模式。
一方面,我们将简要回顾 Day 1 的单例模式,帮助建立起模式之间的连接;另一方面,重点学习如何通过工厂方法封装对象创建逻辑,做到"开闭原则"。

一、Day 1 回顾:单例模式
单例模式的核心要点:
- 保证类的唯一实例。
- 提供一个全局访问点。
- 常见实现包括懒汉式、饿汉式、静态内部类、双重检查锁等。
- 推荐 C++11 使用局部静态变量方式实现线程安全单例。
代码示例(局部静态单例):
cpp
class Logger {
private:
Logger() {}
public:
static Logger* getInstance() {
static Logger instance;
return &instance;
}
void log(const std::string& msg) {
std::cout << "[LOG]: " << msg << std::endl;
}
};
二、本日主题:工厂方法模式
1. 意图说明
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
核心解决:将对象创建的控制权下放到子类中。
2. 结构与角色
+-------------------+ +---------------------+
| Product |<------+ ConcreteProductA |
+-------------------+ +---------------------+
^ ^
| |
+--------------+ +------------------+
| Factory |<-------| ConcreteFactoryA |
+--------------+ +------------------+
| + create() | | + create() |
+--------------+ +------------------+
- Product:抽象产品类
- ConcreteProduct:具体产品类
- Factory:抽象工厂类,声明工厂方法
- ConcreteFactory:具体工厂类,负责生产具体产品
3. 示例:日志系统的多种实现
我们希望在程序中根据不同配置,使用不同类型的日志(如控制台日志、文件日志等)。使用工厂方法模式如下:
(1) 抽象产品接口
cpp
class Logger {
public:
virtual void log(const std::string& msg) = 0;
virtual ~Logger() {}
};
(2) 具体产品实现
cpp
class ConsoleLogger : public Logger {
public:
void log(const std::string& msg) override {
std::cout << "[Console] " << msg << std::endl;
}
};
class FileLogger : public Logger {
public:
void log(const std::string& msg) override {
// 简化处理,真实应写入文件
std::cout << "[File] " << msg << std::endl;
}
};
(3) 工厂接口
cpp
class LoggerFactory {
public:
virtual Logger* createLogger() = 0;
virtual ~LoggerFactory() {}
};
(4) 具体工厂类
cpp
class ConsoleLoggerFactory : public LoggerFactory {
public:
Logger* createLogger() override {
return new ConsoleLogger();
}
};
class FileLoggerFactory : public LoggerFactory {
public:
Logger* createLogger() override {
return new FileLogger();
}
};
(5) 客户端使用
cpp
void testFactory(LoggerFactory* factory) {
Logger* logger = factory->createLogger();
logger->log("This is a test message.");
delete logger;
}
int main() {
ConsoleLoggerFactory consoleFactory;
testFactory(&consoleFactory);
FileLoggerFactory fileFactory;
testFactory(&fileFactory);
return 0;
}
4. 优缺点总结
✅ 优点:
- 满足开闭原则:新增产品时只需添加新工厂和产品类,无需改动原有逻辑。
- 屏蔽具体产品类,解耦创建逻辑与使用逻辑。
❌ 缺点:
- 类的数量增多:每种产品都需要对应工厂类。
- 结构相对复杂,不适合产品类型单一的简单场景。
三、适用场景总结
场景 | 原因 |
---|---|
日志模块支持多种输出方式 | 控制台、文件、网络输出分开实现 |
图像加载库支持多种格式 | 不同格式(PNG/JPEG/GIF)封装为产品类 |
数据库驱动连接 | MySQL/PostgreSQL/SQLite 等切换方便 |
四、今日练习题
✍️ 题目一:
设计一个简化的图像解码系统,要求支持解码 PNG 和 JPEG 图像,使用工厂方法模式设计产品与工厂类结构。
✍️ 题目二:
工厂方法模式如何比简单工厂模式更符合开闭原则?请结合实际项目经验说明。
五、滚动复习:Day 1 要点回顾
- 单例模式确保类只有一个实例,常用于日志、配置、线程池等场景;
- 推荐使用 C++11 局部静态变量实现线程安全单例;
- 注意拷贝构造与赋值运算符需禁用;
- 单例不易测试,可能违反开闭原则。
六、小结与展望
今天我们学习了工厂方法模式,掌握了如何将对象创建交给子类工厂完成,以提高系统的灵活性和可扩展性。明日我们将学习抽象工厂模式(Abstract Factory),它是工厂方法模式的进一步扩展,适用于产品族的创建场景。
持续学习,稳步进阶,设计模式每天一点点,收获将是长远的代码质量提升与架构思维成长。