工厂模式属于对象创建型模式,核心思想是将对象的创建逻辑封装起来,让客户端不需要直接依赖具体类的构造函数,降低代码耦合度。C++中实现工厂模式主要有三种常见形式,分别是简单工厂模式、工厂方法模式和抽象工厂模式,不同形式的适用场景和实现复杂度有所差异。

简单工厂模式
简单工厂模式是最基础的工厂模式实现,通过一个工厂类根据传入的参数决定创建哪种具体产品对象,适合产品类型较少且不会频繁扩展的场景。
实现示例
假设我们需要创建不同类型的日志输出对象,有控制台日志和文件日志两种类型,首先定义统一的日志产品接口:
// 日志产品抽象接口
class Log {
public:
virtual void write(const std::string& content) = 0;
virtual ~Log() = default;
};
// 控制台日志具体产品
class ConsoleLog : public Log {
public:
void write(const std::string& content) override {
std::cout << "控制台输出日志:" << content << std::endl;
}
};
// 文件日志具体产品
class FileLog : public Log {
public:
void write(const std::string& content) override {
std::cout << "文件写入日志:" << content << std::endl;
}
};
接下来实现简单工厂类,根据传入的类型参数创建对应的日志对象:
// 简单工厂类
class LogFactory {
public:
// 日志类型枚举
enum class LogType {
CONSOLE,
FILE
};
static Log* createLog(LogType type) {
switch (type) {
case LogType::CONSOLE:
return new ConsoleLog();
case LogType::FILE:
return new FileLog();
default:
return nullptr;
}
}
};
客户端使用时只需要调用工厂的创建方法,不需要直接实例化具体产品类:
int main() {
// 创建控制台日志
Log* consoleLog = LogFactory::createLog(LogFactory::LogType::CONSOLE);
if (consoleLog) {
consoleLog->write("这是一条测试日志");
delete consoleLog;
}
// 创建文件日志
Log* fileLog = LogFactory::createLog(LogFactory::LogType::FILE);
if (fileLog) {
fileLog->write("这是一条文件日志");
delete fileLog;
}
return 0;
}
简单工厂模式的缺点是如果要新增产品类型,需要修改工厂类的switch逻辑,违反了开闭原则,适合产品类型固定的场景。
工厂方法模式
工厂方法模式是对简单工厂的改进,将工厂类抽象为接口,每个具体产品对应一个具体工厂类,新增产品时只需要新增对应的工厂类,不需要修改原有代码,符合开闭原则。
实现示例
同样以日志场景为例,首先定义产品接口和具体产品类,和简单工厂的产品定义一致,然后定义抽象的工厂接口:
// 抽象工厂接口
class LogFactory {
public:
virtual Log* createLog() = 0;
virtual ~LogFactory() = default;
};
// 控制台日志工厂
class ConsoleLogFactory : public LogFactory {
public:
Log* createLog() override {
return new ConsoleLog();
}
};
// 文件日志工厂
class FileLogFactory : public LogFactory {
public:
Log* createLog() override {
return new FileLog();
}
};
客户端使用时根据需要选择对应的工厂类来创建产品:
int main() {
// 使用控制台日志工厂
LogFactory* consoleFactory = new ConsoleLogFactory();
Log* consoleLog = consoleFactory->createLog();
consoleLog->write("工厂方法模式测试日志");
delete consoleLog;
delete consoleFactory;
// 使用文件日志工厂
LogFactory* fileFactory = new FileLogFactory();
Log* fileLog = fileFactory->createLog();
fileLog->write("文件日志测试内容");
delete fileLog;
delete fileFactory;
return 0;
}
工厂方法模式的优点是扩展性好,新增产品只需要新增对应的产品类和工厂类,不会修改原有代码,缺点是每增加一个产品就要新增一个工厂类,类的数量会增多。
抽象工厂模式
抽象工厂模式用于创建一系列相关或者相互依赖的对象,比如我们需要同时创建不同操作系统的界面组件,每个操作系统有按钮、文本框等不同组件,这些组件是相关的,适合用抽象工厂模式实现。
实现示例
首先定义两个产品接口,分别是按钮和文本框:
// 按钮抽象产品
class Button {
public:
virtual void render() = 0;
virtual ~Button() = default;
};
// 文本框抽象产品
class TextBox {
public:
virtual void input() = 0;
virtual ~TextBox() = default;
};
// Windows按钮具体产品
class WindowsButton : public Button {
public:
void render() override {
std::cout << "渲染Windows风格按钮" << std::endl;
}
};
// Windows文本框具体产品
class WindowsTextBox : public TextBox {
public:
void input() override {
std::cout << "Windows文本框输入内容" << std::endl;
}
};
// Mac按钮具体产品
class MacButton : public Button {
public:
void render() override {
std::cout << "渲染Mac风格按钮" << std::endl;
}
};
// Mac文本框具体产品
class MacTextBox : public TextBox {
public:
void input() override {
std::cout << "Mac文本框输入内容" << std::endl;
}
};
然后定义抽象工厂接口,包含创建所有相关产品的方法:
// 抽象工厂接口
class GUIFactory {
public:
virtual Button* createButton() = 0;
virtual TextBox* createTextBox() = 0;
virtual ~GUIFactory() = default;
};
// Windows工厂
class WindowsFactory : public GUIFactory {
public:
Button* createButton() override {
return new WindowsButton();
}
TextBox* createTextBox() override {
return new WindowsTextBox();
}
};
// Mac工厂
class MacFactory : public GUIFactory {
public:
Button* createButton() override {
return new MacButton();
}
TextBox* createTextBox() override {
return new MacTextBox();
}
};
客户端使用时只需要选择对应的工厂,就可以创建同一系列的所有相关产品:
int main() {
// 使用Windows工厂创建系列组件
GUIFactory* winFactory = new WindowsFactory();
Button* winBtn = winFactory->createButton();
TextBox* winTextBox = winFactory->createTextBox();
winBtn->render();
winTextBox->input();
delete winBtn;
delete winTextBox;
delete winFactory;
// 使用Mac工厂创建系列组件
GUIFactory* macFactory = new MacFactory();
Button* macBtn = macFactory->createButton();
TextBox* macTextBox = macFactory->createTextBox();
macBtn->render();
macTextBox->input();
delete macBtn;
delete macTextBox;
delete macFactory;
return 0;
}
抽象工厂模式适合需要创建多个相关产品系列的场景,缺点是如果要新增一个产品类型,比如新增下拉框,需要修改所有工厂类的接口和实现,扩展成本较高。
三种工厂模式的选择建议
- 如果产品类型少且不会频繁扩展,优先选择简单工厂模式,实现简单,代码量少
- 如果产品类型会频繁扩展,需要符合开闭原则,选择工厂方法模式
- 如果需要创建多个相关的产品系列,选择抽象工厂模式
在实际C++项目中使用工厂模式时,需要注意内存管理,示例中使用了裸指针,实际开发中可以结合智能指针比如std::unique_ptr来管理对象生命周期,避免内存泄漏问题。