工厂模式
前言
在我实现工厂模式的代码时,我遇到了实现这个模型的一些问题,并且继续深究之后,发现理论与实际的基础都缺乏,并因此记录下这次完整的学习过程。
工厂模式封装创建类的过程,使用统一的接口来实例化不同的产品类,符合开放封闭的原则(对接口开放,对修改封闭),解决的是创建“什么对象”的问题,单例模式解决的是创建“多少对象“的问题。
实现工厂模式
正确代码示例:
#include <iostream>
using namespace std;
enum ProductType {
TypeA,
TypeB,
TypeC
};
class Product {
public:
// 错误修复1:删除构造函数的virtual关键字
Product() {};
virtual void eat() = 0; // 纯虚函数,标记抽象类
// 错误修复2:为纯虚析构提供空实现
virtual ~Product() {};
};
class ProductA : public Product {
public:
ProductA() {
cout << "Produce A" << endl;
}
void eat() { cout << "eat A" << endl; }
~ProductA() {
cout << "~ProductA" << endl;
}
};
class ProductB : public Product {
public:
ProductB() {
cout << "Produce B" << endl;
}
void eat() { cout << "eat B" << endl; }
~ProductB() {
cout << "~ProductB" << endl;
}
};
class Factory {
public:
Factory() : product(nullptr) {}
Product* produceProduct(ProductType productType) {
// 错误修复3:创建新对象前释放旧对象,避免内存泄漏
if (product) {
delete product;
product = nullptr;
}
switch (productType) {
case TypeA:
product = new ProductA();
break;
case TypeB:
product = new ProductB();
break;
default:
product = new ProductA();
break;
}
return product;
}
~Factory() {
if (product) {
delete product;
product = nullptr;
}
}
private:
Product* product;
};
void testFuncEat() {
Factory f;
Product* p = f.produceProduct(TypeA);
p->eat();
}
int main() {
testFuncEat();
return 0;
}
其中需要修复的地方就是我之前放下的错误:
犯下的错误与思考
错误一
构造函数不能声明为:virtual
virtual Product(){}; // 错误1:构造函数声明为virtual
虚表指针的初始化时机就是在构造函数中,virtual关键字用于支持运行时多态,依赖对象的虚函数表(vtable)。但构造函数的作用是创建并初始化对象,在对象完全创建前,虚函数表尚未初始化,无法实现多态;且调用构造函数时必须明确具体类类型,无法延迟决定调用哪个构造函数,C++标准禁止构造函数为虚函数。
错误二
析构函数无法无法定义为纯虚函数
virtual ~Product() {}; // 错误2:纯虚析构仅声明未定义
纯虚析构的=0仅用于标记类为抽象类,而非“无需实现”。析构函数遵循“先子类、后父类”的链式调用规则,子类析构执行完后会自动调用父类析构,若父类纯虚析构无实现,链接器会找不到对应函数体,导致报错。
错误三
构建新的对象前没有考虑原始资源的释放。
// 修复3:创建新对象前释放旧对象,避免内存泄漏
if (product) {
delete product;
product = nullptr;
}
明确内存释放责任,由Factory统一管理product指针的生命周期,外部仅使用指针,不执行delete操作;同时在Factory创建新对象前,释放旧对象,避免内存泄漏。