1. 工厂模式的核心价值
工厂模式是面向对象编程中最常用的设计模式之一,它解决了对象创建过程中的一系列关键问题。想象一下你在开发一个图形编辑器,需要创建圆形、矩形、三角形等多种图形对象。如果直接在代码各处使用new操作符创建具体对象,会导致代码高度耦合,难以维护。这就是工厂模式要解决的核心痛点。
在实际项目中,我见过太多因为对象创建逻辑混乱而导致的维护噩梦。比如某个电商系统中有十几种支付方式,如果创建支付对象的逻辑散落在各处,当需要修改某种支付方式的初始化参数时,就得在整个代码库中大海捞针。工厂模式通过将对象创建集中管理,完美解决了这个问题。
2. 简单工厂模式实现
2.1 基本结构实现
简单工厂模式是最基础的实现形式,它通过一个工厂类封装对象的创建逻辑。下面是一个典型的C++实现:
cpp复制class Product {
public:
virtual ~Product() {}
virtual void operation() = 0;
};
class ConcreteProductA : public Product {
public:
void operation() override {
std::cout << "ConcreteProductA operation" << std::endl;
}
};
class ConcreteProductB : public Product {
public:
void operation() override {
std::cout << "ConcreteProductB operation" << std::endl;
}
};
class SimpleFactory {
public:
static Product* createProduct(const std::string& type) {
if (type == "A") {
return new ConcreteProductA();
} else if (type == "B") {
return new ConcreteProductB();
}
return nullptr;
}
};
这种实现方式有几个关键点需要注意:
- 产品类继承自同一个抽象基类
- 工厂类提供静态创建方法
- 通过参数决定创建哪种具体产品
2.2 使用场景与限制
简单工厂模式最适合以下场景:
- 对象创建逻辑相对简单
- 产品类型数量有限且不太可能频繁变化
- 客户端不需要关心具体的创建细节
但在实际项目中,我发现这种模式有几个明显局限:
- 当新增产品类型时,必须修改工厂类的代码,违反了开闭原则
- 产品创建逻辑集中在一个方法中,随着产品增多会变得臃肿
- 难以扩展为层次化的产品结构
3. 工厂方法模式进阶
3.1 多态工厂实现
工厂方法模式通过引入抽象工厂类解决了简单工厂的扩展性问题。每个具体工厂只负责创建一种产品:
cpp复制class Factory {
public:
virtual ~Factory() {}
virtual Product* createProduct() = 0;
};
class ConcreteFactoryA : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductA();
}
};
class ConcreteFactoryB : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductB();
}
};
这种实现方式的特点是:
- 每个具体工厂类只负责创建一种产品
- 新增产品类型时只需添加新的工厂类
- 客户端代码依赖于抽象工厂而非具体实现
3.2 实际应用技巧
在真实项目中使用工厂方法模式时,我总结了几个实用技巧:
- 工厂对象管理:可以使用单例模式管理工厂实例,避免重复创建工厂对象
cpp复制class ConcreteFactoryA : public Factory {
public:
static Factory& getInstance() {
static ConcreteFactoryA instance;
return instance;
}
// ...
};
- 模板工厂:利用C++模板实现通用工厂
cpp复制template<typename T>
class TemplateFactory : public Factory {
public:
Product* createProduct() override {
return new T();
}
};
- 注册机制:实现动态工厂注册,支持运行时扩展
cpp复制class FactoryRegistry {
public:
using Creator = std::function<Product*()>;
void registerFactory(const std::string& name, Creator creator) {
registry_[name] = creator;
}
Product* createProduct(const std::string& name) {
auto it = registry_.find(name);
if (it != registry_.end()) {
return it->second();
}
return nullptr;
}
private:
std::unordered_map<std::string, Creator> registry_;
};
4. 抽象工厂模式解析
4.1 产品族创建方案
抽象工厂模式用于创建相关或依赖对象的家族,而不需要指定具体类。这在GUI库、跨平台开发等场景特别有用:
cpp复制class Button {
public:
virtual void render() = 0;
};
class WindowsButton : public Button {
void render() override { /* Windows风格渲染 */ }
};
class MacButton : public Button {
void render() override { /* Mac风格渲染 */ }
};
class GUIFactory {
public:
virtual Button* createButton() = 0;
virtual Checkbox* createCheckbox() = 0;
};
class WindowsFactory : public GUIFactory {
Button* createButton() override { return new WindowsButton(); }
Checkbox* createCheckbox() override { return new WindowsCheckbox(); }
};
class MacFactory : public GUIFactory {
Button* createButton() override { return new MacButton(); }
Checkbox* createCheckbox() override { return new MacCheckbox(); }
};
4.2 跨平台应用实例
在开发跨平台应用时,抽象工厂模式特别有用。以下是一个实际项目中的架构示例:
cpp复制class PlatformFactory {
public:
static GUIFactory* getFactory() {
#ifdef _WIN32
return new WindowsFactory();
#elif __APPLE__
return new MacFactory();
#elif __linux__
return new LinuxFactory();
#endif
}
};
// 客户端代码
GUIFactory* factory = PlatformFactory::getFactory();
Button* btn = factory->createButton();
btn->render();
这种设计确保了:
- 平台相关代码集中管理
- 客户端代码与具体平台解耦
- 新增平台支持只需添加新的工厂类
5. 现代C++实现技巧
5.1 智能指针集成
在现代C++中,使用智能指针可以更好地管理工厂创建的对象生命周期:
cpp复制std::unique_ptr<Product> Factory::createProduct() {
return std::make_unique<ConcreteProduct>();
}
这种改进带来了几个好处:
- 自动内存管理,防止内存泄漏
- 明确所有权语义
- 与STL容器配合更好
5.2 可变参数模板支持
C++11的可变参数模板可以让工厂接口更灵活:
cpp复制template<typename ProductType, typename... Args>
class AdvancedFactory {
public:
static std::unique_ptr<Product> create(Args&&... args) {
return std::make_unique<ProductType>(std::forward<Args>(args)...);
}
};
// 使用示例
auto product = AdvancedFactory<ConcreteProduct, int, string>::create(42, "param");
6. 性能优化与线程安全
6.1 对象池技术
对于频繁创建销毁的对象,可以结合对象池模式优化性能:
cpp复制class ProductPool {
public:
void returnProduct(Product* product) {
std::lock_guard<std::mutex> lock(mutex_);
pool_.push_back(product);
}
Product* getProduct() {
std::lock_guard<std::mutex> lock(mutex_);
if (pool_.empty()) {
return factory_->createProduct();
}
auto product = pool_.back();
pool_.pop_back();
return product;
}
private:
std::vector<Product*> pool_;
std::mutex mutex_;
Factory* factory_;
};
6.2 线程安全考量
在多线程环境中使用工厂模式需要注意:
- 工厂方法本身应该是线程安全的
- 考虑使用双重检查锁定模式优化性能
- 静态局部变量初始化是线程安全的(C++11以后)
cpp复制Factory& getFactory() {
static Factory instance; // 线程安全初始化
return instance;
}
7. 测试与模拟实践
7.1 单元测试策略
工厂模式的测试要点包括:
- 验证工厂返回的对象类型正确
- 测试边界条件和错误输入处理
- 模拟测试异常情况
cpp复制TEST(FactoryTest, CreatesCorrectType) {
auto product = Factory::createProduct("A");
ASSERT_NE(product, nullptr);
EXPECT_TRUE(dynamic_cast<ConcreteProductA*>(product) != nullptr);
delete product;
}
7.2 模拟对象应用
在测试中使用模拟工厂可以隔离依赖:
cpp复制class MockFactory : public Factory {
public:
MOCK_METHOD(Product*, createProduct, (), (override));
};
TEST(FactoryTest, UsesMockFactory) {
MockFactory mock;
EXPECT_CALL(mock, createProduct())
.WillOnce(Return(new MockProduct));
auto product = mock.createProduct();
// 验证使用product的行为
delete product;
}
8. 设计考量与替代方案
8.1 何时不使用工厂模式
虽然工厂模式很强大,但并非所有场景都适用:
- 对象创建逻辑极其简单时
- 性能敏感的代码路径
- 产品类型极少且不会变化
8.2 相关模式对比
与其他创建型模式的比较:
| 模式 | 适用场景 | 复杂度 | 灵活性 |
|---|---|---|---|
| 简单工厂 | 少量固定类型 | 低 | 低 |
| 工厂方法 | 单一产品扩展 | 中 | 中 |
| 抽象工厂 | 产品族创建 | 高 | 高 |
| 建造者 | 复杂对象构造 | 高 | 高 |
| 原型 | 克隆现有实例 | 中 | 中 |
在实际架构设计中,我经常将工厂模式与其他模式结合使用。比如用工厂创建建造者,或者让工厂返回原型对象的克隆。这种组合可以发挥各模式的优势,创建更灵活的对象创建机制。