抽象工厂模式 (Abstract Factory)
抽象工厂模式 是一种创建型设计模式,提供一个接口,用于创建一组相关或互相依赖的对象,而无需指定它们的具体类。
意图
- 提供一个创建一组相关对象的接口,而无需指定它们的具体类。
- 解决产品对象之间的相互依赖问题,使得一组对象能协同工作。
使用场景
- 需要创建一组相关对象:
- 如 GUI 程序中,窗口、按钮、菜单等需要统一的外观风格。
- 需要保证对象之间的兼容性:
- 如游戏开发中,不同种族的士兵和建筑需要互相匹配。
- 需要隐藏具体实现:
- 客户端代码只依赖于产品接口,具体实现被封装。
参与者角色
- 抽象工厂 (Abstract Factory)
- 声明一组用于创建相关对象的接口。
- 具体工厂 (Concrete Factory)
- 实现抽象工厂的接口,创建具体的产品。
- 抽象产品 (Abstract Product)
- 定义所有产品的公共接口。
- 具体产品 (Concrete Product)
- 实现抽象产品的接口,为具体工厂生产的对象。
示例代码
以下示例展示了如何使用抽象工厂模式为不同操作系统创建相关的 GUI 组件(按钮和窗口)。
#include <iostream>
#include <memory>
// 抽象产品 A: 按钮
class Button {
public:
virtual void render() const = 0;
virtual ~Button() {}
};
// 具体产品 A1: Windows 按钮
class WindowsButton : public Button {
public:
void render() const override {
std::cout << "Rendering Windows Button" << std::endl;
}
};
// 具体产品 A2: Mac 按钮
class MacButton : public Button {
public:
void render() const override {
std::cout << "Rendering Mac Button" << std::endl;
}
};
// 抽象产品 B: 窗口
class Window {
public:
virtual void render() const = 0;
virtual ~Window() {}
};
// 具体产品 B1: Windows 窗口
class WindowsWindow : public Window {
public:
void render() const override {
std::cout << "Rendering Windows Window" << std::endl;
}
};
// 具体产品 B2: Mac 窗口
class MacWindow : public Window {
public:
void render() const override {
std::cout << "Rendering Mac Window" << std::endl;
}
};
// 抽象工厂
class GUIFactory {
public:
virtual std::unique_ptr<Button> createButton() const = 0;
virtual std::unique_ptr<Window> createWindow() const = 0;
virtual ~GUIFactory() {}
};
// 具体工厂 1: Windows 工厂
class WindowsFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() const override {
return std::make_unique<WindowsButton>();
}
std::unique_ptr<Window> createWindow() const override {
return std::make_unique<WindowsWindow>();
}
};
// 具体工厂 2: Mac 工厂
class MacFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() const override {
return std::make_unique<MacButton>();
}
std::unique_ptr<Window> createWindow() const override {
return std::make_unique<MacWindow>();
}
};
// 主函数
int main() {
// 选择具体工厂
std::unique_ptr<GUIFactory> factory = std::make_unique<WindowsFactory>();
// 使用工厂创建产品
auto button = factory->createButton();
auto window = factory->createWindow();
button->render(); // 输出:Rendering Windows Button
window->render(); // 输出:Rendering Windows Window
// 切换到另一种具体工厂
factory = std::make_unique<MacFactory>();
button = factory->createButton();
window = factory->createWindow();
button->render(); // 输出:Rendering Mac Button
window->render(); // 输出:Rendering Mac Window
return 0;
}
代码解析
1. 抽象产品类
定义了产品的公共接口,确保产品类型的一致性:
class Button {
public:
virtual void render() const = 0;
virtual ~Button() {}
};
2. 具体产品类
实现了抽象产品接口,并提供具体功能:
class WindowsButton : public Button {
public:
void render() const override {
std::cout << "Rendering Windows Button" << std::endl;
}
};
3. 抽象工厂
定义了创建一组相关产品的接口:
class GUIFactory {
public:
virtual std::unique_ptr<Button> createButton() const = 0;
virtual std::unique_ptr<Window> createWindow() const = 0;
virtual ~GUIFactory() {}
};
4. 具体工厂
实现了抽象工厂接口,负责生产具体的产品:
class WindowsFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() const override {
return std::make_unique<WindowsButton>();
}
std::unique_ptr<Window> createWindow() const override {
return std::make_unique<WindowsWindow>();
}
};
5. 主函数
客户端代码通过工厂接口创建产品,无需知道具体产品的实现:
std::unique_ptr<GUIFactory> factory = std::make_unique<WindowsFactory>();
auto button = factory->createButton();
auto window = factory->createWindow();
button->render();
window->render();
优缺点
优点
- 解耦:客户端代码只依赖抽象工厂和抽象产品,与具体实现无关。
- 保证产品一致性:抽象工厂确保一组对象是兼容的。
- 扩展性强:可以通过新增具体工厂扩展系统。
缺点
- 增加复杂性:每增加一组产品需要新增抽象类和具体类。
- 灵活性受限:对现有产品结构的修改可能需要更新所有工厂。
适用场景
- 跨平台开发:如为不同操作系统设计统一的 GUI。
- 产品族设计:如游戏中不同种族的士兵和建筑需要互相匹配。
- 动态扩展产品族:如增加新的平台支持。
改进与扩展
-
结合配置文件
动态选择具体工厂,根据运行时条件决定产品族的创建:std::unique_ptr<GUIFactory> factory; if (platform == "Windows") { factory = std::make_unique<WindowsFactory>(); } else { factory = std::make_unique<MacFactory>(); }
-
引入依赖注入框架
通过依赖注入简化工厂选择的逻辑,使得代码更易于维护和测试。
总结
抽象工厂模式通过提供一个接口,用于创建一组相关对象,实现了创建逻辑的集中化和产品族之间的兼容性。
它适用于需要跨平台开发或产品族设计的场景。