以下是针对C++03标准的抽象工厂模式(Abstract Factory)的详细讲解,包含模式原理、C++03适配实现、代码示例及使用说明,适合需要兼容旧标准的开发场景。
一、抽象工厂模式基础(C++03语境)
抽象工厂模式是创建型模式的重要成员,专注于一系列相互关联的产品族创建。在C++03环境中,虽然缺少智能指针和现代语法,但通过原始指针、虚函数和类继承,依然能完整实现其核心功能:
- 核心目标:提供一个接口,用于创建多个产品族中的产品,且客户端无需知道具体产品的类型。
- 典型场景:跨平台开发(如Windows/Linux组件)、数据库驱动套件(如MySQL/Oracle连接+命令对象)等需要配套产品的场景。
二、C++03中的核心角色实现
抽象工厂模式包含4个核心角色,在C++03中通过类层次结构实现:
角色 | 定义与实现要点(C++03) |
---|---|
抽象产品(Abstract Product) | 纯虚类,定义某类产品的接口(如按钮、文本框),包含纯虚方法和虚析构函数(避免析构泄漏)。 |
具体产品(Concrete Product) | 继承抽象产品,实现具体功能(如Windows按钮),重写虚函数时无需override 关键字。 |
抽象工厂(Abstract Factory) | 纯虚类,声明创建各抽象产品的工厂方法(如createButton() ),返回抽象产品指针。 |
具体工厂(Concrete Factory) | 继承抽象工厂,实现工厂方法,通过new 创建并返回具体产品指针(需客户端手动管理内存)。 |
三、完整代码实现(C++03)
以"数据库访问组件"为例,实现支持MySQL和Oracle的"连接"与"命令"产品族:
cpp
#include <iostream>
#include <string>
// 1. 抽象产品A:数据库连接
class DBConnection {
public:
virtual void connect() const = 0; // 连接数据库
virtual void disconnect() const = 0; // 断开连接
virtual ~DBConnection() {} // 虚析构函数
};
// 1. 抽象产品B:数据库命令
class DBCommand {
public:
virtual void execute(const std::string& sql) const = 0; // 执行SQL
virtual ~DBCommand() {}
};
// 2. 具体产品A1:MySQL连接
class MySQLConnection : public DBConnection {
public:
void connect() const {
std::cout << "MySQL: 连接到数据库服务器" << std::endl;
}
void disconnect() const {
std::cout << "MySQL: 断开数据库连接" << std::endl;
}
};
// 2. 具体产品B1:MySQL命令
class MySQLCommand : public DBCommand {
public:
void execute(const std::string& sql) const {
std::cout << "MySQL: 执行SQL -> " << sql << std::endl;
}
};
// 2. 具体产品A2:Oracle连接
class OracleConnection : public DBConnection {
public:
void connect() const {
std::cout << "Oracle: 连接到数据库服务器" << std::endl;
}
void disconnect() const {
std::cout << "Oracle: 断开数据库连接" << std::endl;
}
};
// 2. 具体产品B2:Oracle命令
class OracleCommand : public DBCommand {
public:
void execute(const std::string& sql) const {
std::cout << "Oracle: 执行SQL -> " << sql << std::endl;
}
};
// 3. 抽象工厂:数据库组件工厂
class DBFactory {
public:
virtual DBConnection* createConnection() const = 0; // 创建连接
virtual DBCommand* createCommand() const = 0; // 创建命令
virtual ~DBFactory() {}
};
// 4. 具体工厂1:MySQL工厂
class MySQLFactory : public DBFactory {
public:
DBConnection* createConnection() const {
return new MySQLConnection(); // C++03用new创建,返回原始指针
}
DBCommand* createCommand() const {
return new MySQLCommand();
}
};
// 4. 具体工厂2:Oracle工厂
class OracleFactory : public DBFactory {
public:
DBConnection* createConnection() const {
return new OracleConnection();
}
DBCommand* createCommand() const {
return new OracleCommand();
}
};
// 客户端:使用数据库组件
class DataAccess {
private:
DBFactory* factory;
DBConnection* conn;
DBCommand* cmd;
public:
// 构造函数:接收具体工厂
DataAccess(DBFactory* f) : factory(f), conn(0), cmd(0) {
conn = factory->createConnection();
cmd = factory->createCommand();
}
// 析构函数:手动释放内存(C++03关键步骤)
~DataAccess() {
delete cmd;
delete conn;
// 工厂由外部管理,此处不删除
}
// 业务方法:执行数据库操作
void doOperation() const {
conn->connect();
cmd->execute("SELECT * FROM users");
conn->disconnect();
}
};
// 演示代码
int main() {
// 场景1:使用MySQL
std::cout << "=== MySQL操作 ===" << std::endl;
MySQLFactory mysqlFactory;
DataAccess mysqlAccess(&mysqlFactory);
mysqlAccess.doOperation();
// 场景2:使用Oracle
std::cout << "\n=== Oracle操作 ===" << std::endl;
OracleFactory oracleFactory;
DataAccess oracleAccess(&oracleFactory);
oracleAccess.doOperation();
return 0;
}
四、C++03实现细节说明
-
内存管理策略
- C++03没有智能指针,必须显式使用
new
创建对象,并用delete
释放(如DataAccess
析构函数中释放conn
和cmd
)。 - 工厂对象建议使用栈分配(如
MySQLFactory mysqlFactory
),避免动态内存管理复杂度过高。 - 严格遵循"谁创建谁释放"原则:
DataAccess
创建产品,因此负责释放;工厂由外部传入,不负责释放。
- C++03没有智能指针,必须显式使用
-
多态保障
- 所有抽象类(如
DBConnection
)必须定义虚析构函数,否则删除子类对象时可能只调用基类析构函数,导致内存泄漏。 - 子类重写虚函数时,函数签名(参数、返回值、
const
属性)必须与基类完全一致(C++03无override
检查,需手动保证)。
- 所有抽象类(如
-
产品族兼容性
- 同一具体工厂创建的产品(如
MySQLFactory
的MySQLConnection
和MySQLCommand
)天然兼容,确保数据库操作正常协同。 - 切换数据库类型时,只需替换具体工厂(如
OracleFactory
),客户端代码(DataAccess
)无需修改,符合开闭原则。
- 同一具体工厂创建的产品(如
五、C++03环境下的优缺点
优点
- 隔离具体实现 :客户端代码(如
DataAccess
)仅依赖抽象接口,与MySQLConnection
等具体类解耦。 - 产品族一致性:确保同一工厂的产品可正确协作(如MySQL连接只能搭配MySQL命令)。
- 便于扩展产品族 :新增数据库(如PostgreSQL)时,只需添加
PostgreSQLFactory
及对应产品,无需修改现有代码。
缺点(C++03特有)
- 内存管理复杂 :需手动
delete
对象,易出现泄漏或二次释放问题(可通过工厂模式+单例模式优化)。 - 类数量膨胀:每增加一个产品族或产品类型,需新增多个类(如3个数据库×2个产品=6个具体产品类+3个工厂类)。
- 扩展新产品类型困难 :若需新增产品(如
DBReader
),需修改抽象工厂接口及所有具体工厂,违反开闭原则。
六、使用建议(C++03项目)
- 适合场景:产品族稳定(新增产品族频繁,但新增产品类型少)的项目,如跨平台组件库、数据库驱动套件。
- 内存优化 :可将具体工厂设计为单例(避免重复创建),产品对象可考虑对象池模式(减少
new/delete
开销)。 - 与工厂方法结合 :若需新增产品类型(如
DBReader
),可在具体工厂中用工厂方法模式实现该产品的创建,降低修改成本。
总结
在C++03中实现抽象工厂模式,虽然需要手动管理内存和注意多态细节,但其核心价值------封装产品族创建、保证组件兼容性、简化客户端使用------依然显著。对于需要兼容旧标准且涉及多组关联产品创建的场景,这是一种可靠的设计选择。