当前位置: 首页 > news >正文

设计模式(C++)详解—抽象工厂模式 (Abstract Factory)(2)

抽象工厂模式(Abstract Factory)超级详解

引言:为什么我们需要"工厂的工厂"?

想象一下,你要开一家大型连锁餐厅,需要为不同地区(中式、西式、日式)提供完整的餐饮解决方案。你不会为每个菜品单独找供应商,而是会找一整套的食材供应商——中式餐厅找中式食材供应商,西式餐厅找西式食材供应商。这就是抽象工厂模式的精髓!

抽象工厂模式就像是这个"餐饮解决方案总承包商",它能够创建一整套相互关联的产品,而客户端不需要关心具体是怎么创建的。让我们深入探索这个强大的设计模式吧!

1. 背景与核心概念

1.1 设计模式演化史

抽象工厂模式诞生于1994年,由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides(俗称"四人帮")在经典著作《设计模式:可复用面向对象软件的基础》中提出。这个模式的出现解决了当时软件开发中的一个重要问题:如何创建一系列相关或依赖的对象,而不需要指定它们的具体类

在面向对象编程的早期,开发者经常遇到这样的困境:

  • 系统需要支持多个不同的产品家族
  • 这些家族中的产品需要一起使用,不能混搭
  • 添加新的产品家族时,不希望修改已有的代码

抽象工厂模式完美解决了这些问题,成为了创建型模式中的重要成员。

1.2 核心概念深度解析

产品族(Product Family) vs 产品等级(Product Hierarchy)

让我们用一个生活中的例子来理解这两个概念:

假设我们有两个电子产品家族:苹果生态华为生态

  • 每个生态都有手机、平板、笔记本三种产品
  • 这就形成了两个产品族(苹果族、华为族)
  • 每个族内有三个产品等级(手机等级、平板等级、笔记本等级)
电子产品
苹果生态
华为生态
iPhone
iPad
MacBook
Mate手机
MatePad
MateBook
抽象工厂的四大天王
  1. AbstractFactory(抽象工厂):声明创建抽象产品的接口
  2. ConcreteFactory(具体工厂):实现抽象工厂接口,创建具体产品
  3. AbstractProduct(抽象产品):声明产品对象的接口
  4. ConcreteProduct(具体产品):实现抽象产品接口,定义具体产品

2. 设计意图与考量

2.1 为什么选择抽象工厂模式?

优势一览表
优势说明实际例子
产品兼容性确保创建的产品能够协同工作苹果设备间的无缝连接
客户端解耦客户端只依赖抽象接口,不依赖具体实现应用程序不关心是Windows还是Mac按钮
易于切换通过更换具体工厂,轻松切换整个产品族从MySQL切换到PostgreSQL
符合开闭原则新增产品族无需修改现有代码新增Dark主题不影响Light主题
适用场景
  1. 跨平台应用开发:为不同操作系统创建相应的UI组件
  2. 数据库访问层:支持多种数据库系统,保持接口一致
  3. 游戏开发:为不同游戏风格创建相应的角色、道具、场景
  4. 主题系统:为应用程序提供可切换的视觉主题
  5. 硬件抽象层:为不同硬件平台提供统一的接口

2.2 设计时的关键考量

扩展性困境

抽象工厂模式有一个著名的"扩展性困境":

  • 增加新产品族:很容易,只需实现新的具体工厂
  • 增加新产品种类:很困难,需要修改所有工厂接口
抽象工厂
具体工厂A
具体工厂B
产品A1
产品A2
产品B1
产品B2
新增具体工厂C
产品C1
产品C2
新增产品3

如图所示,纵向扩展(新增工厂)很容易,但横向扩展(新增产品)很困难。

3. 实例与应用场景

3.1 跨平台UI库完整实现

让我们实现一个完整的跨平台UI组件库,支持Windows和Mac两种风格:

// ==================== 抽象产品接口 ====================
// 按钮抽象接口
class IButton {
public:virtual ~IButton() = default;virtual void render() const = 0;virtual void onClick() const = 0;virtual std::string getDescription() const = 0;
};// 文本框抽象接口
class ITextBox {
public:virtual ~ITextBox() = default;virtual void render() const = 0;virtual void onInput(const std::string& text) = 0;virtual std::string getText() const = 0;virtual std::string getDescription() const = 0;
};// 复选框抽象接口
class ICheckBox {
public:virtual ~ICheckBox() = default;virtual void render() const = 0;virtual void onToggle(bool checked) = 0;virtual bool isChecked() const = 0;virtual std::string getDescription() const = 0;
};// ==================== 具体产品实现 ====================
// Windows按钮
class WindowsButton : public IButton {
private:std::string label;public:explicit WindowsButton(const std::string& lbl = "Button") : label(lbl) {}void render() const override {std::cout << "🪟 渲染Windows风格按钮: " << label << std::endl;std::cout << "   ┌─────────────────┐" << std::endl;std::cout << "   │     " << std::setw(10) << std::left << label << "     │" << std::endl;std::cout << "   └─────────────────┘" << std::endl;}void onClick() const override {std::cout << "💻 Windows按钮被点击: " << label << std::endl;}std::string getDescription() const override {return "Windows风格按钮 - " + label;}
};// Mac按钮
class MacButton : public IButton {
private:std::string label;public:explicit MacButton(const std::string& lbl = "Button") : label(lbl) {}void render() const override {std::cout << "🍎 渲染Mac风格按钮: " << label << std::endl;std::cout << "   ╔═════════════════╗" << std::endl;std::cout << "   ║  " << std::setw(12) << std::left << label << "  ║" << std::endl;std::cout << "   ╚═════════════════╝" << std::endl;}void onClick() const override {std::cout << "🖱️  Mac按钮被点击: " << label << std::endl;}std::string getDescription() const override {return "Mac风格按钮 - " + label;}
};// Windows文本框
class WindowsTextBox : public ITextBox {
private:std::string text;public:void render() const override {std::cout << "🪟 渲染Windows风格文本框:" << std::endl;std::cout << "   ┌─────────────────────────────────┐" << std::endl;if (text.empty()) {std::cout << "   │ 请输入文本...                  │" << std::endl;} else {std::cout << "   │ " << std::setw(30) << std::left << text.substr(0, 30) << " │" << std::endl;}std::cout << "   └─────────────────────────────────┘" << std::endl;}void onInput(const std::string& inputText) override {text = inputText;std::cout << "⌨️  Windows文本框输入: " << text << std::endl;}std::string getText() const override { return text; }std::string getDescription() const override {return "Windows风格文本框 - 内容: " + (text.empty() ? "空" : text.substr(0, 10) + "...");}
};// Mac文本框
class MacTextBox : public ITextBox {
private:std::string text;public:void render() const override {std::cout << "🍎 渲染Mac风格文本框:" << std::endl;std::cout << "   ╔═════════════════════════════════╗" << std::endl;if (text.empty()) {std::cout << "   ║  请输入文本...                ║" << std::endl;} else {std::cout << "   ║  " << std::setw(28) << std::left << text.substr(0, 28) << "  ║" << std::endl;}std::cout << "   ╚═════════════════════════════════╝" << std::endl;}void onInput(const std::string& inputText) override {text = inputText;std::cout << "⌨️  Mac文本框输入: " << text << std::endl;}std::string getText() const override { return text; }std::string getDescription() const override {return "Mac风格文本框 - 内容: " + (text.empty() ? "空" : text.substr(0, 10) + "...");}
};// Windows复选框
class WindowsCheckBox : public ICheckBox {
private:bool checked;std::string label;public:explicit WindowsCheckBox(const std::string& lbl = "Checkbox", bool chk = false) : label(lbl), checked(chk) {}void render() const override {std::cout << "🪟 渲染Windows风格复选框: " << label << std::endl;std::cout << "   [" << (checked ? "✓" : " ") << "] " << label << std::endl;}void onToggle(bool isChecked) override {checked = isChecked;std::cout << "✅ Windows复选框" << (checked ? "选中" : "取消") << ": " << label << std::endl;}bool isChecked() const override { return checked; }std::string getDescription() const override {return "Windows风格复选框 - " + label + " : " + (checked ? "选中" : "未选中");}
};// Mac复选框
class MacCheckBox : public ICheckBox {
private:bool checked;std::string label;public:explicit MacCheckBox(const std::string& lbl = "Checkbox", bool chk = false) : label(lbl), checked(chk) {}void render() const override {std::cout << "🍎 渲染Mac风格复选框: " << label << std::endl;std::cout << "   [" << (checked ? "✔" : " ") << "] " << label << std::endl;}void onToggle(bool isChecked) override {checked = isChecked;std::cout << "✅ Mac复选框" << (checked ? "选中" : "取消") << ": " << label << std::endl;}bool isChecked() const override { return checked; }std::string getDescription() const override {return "Mac风格复选框 - " + label + " : " + (checked ? "选中" : "未选中");}
};// ==================== 抽象工厂接口 ====================
class IUIFactory {
public:virtual ~IUIFactory() = default;virtual std::unique_ptr<IButton> createButton(const std::string& label) const = 0;virtual std::unique_ptr<ITextBox> createTextBox() const = 0;virtual std::unique_ptr<ICheckBox> createCheckBox(const std::string& label, bool checked = false) const = 0;virtual std::string getFactoryName() const = 0;
};// ==================== 具体工厂实现 ====================
class WindowsUIFactory : public IUIFactory {
public:std::unique_ptr<IButton> createButton(const std::string& label) const override {return std::make_unique<WindowsButton>(label);}std::unique_ptr<ITextBox> createTextBox() const override {return std::make_unique<WindowsTextBox>();}std::unique_ptr<ICheckBox> createCheckBox(const std::string& label, bool checked) const override {return std::make_unique<WindowsCheckBox>(label, checked);}std::string getFactoryName() const override {return "Windows UI Factory";}
};class MacUIFactory : public IUIFactory {
public:std::unique_ptr<IButton> createButton(const std::string& label) const override {return std::make_unique<MacButton>(label);}std::unique_ptr<ITextBox> createTextBox() const override {return std::make_unique<MacTextBox>();}std::unique_ptr<ICheckBox> createCheckBox(const std::string& label, bool checked) const override {return std::make_unique<MacCheckBox>(label, checked);}std::string getFactoryName() const override {return "Mac UI Factory";}
};// ==================== 客户端代码 ====================
class Application {
private:std::unique_ptr<IUIFactory> factory;std::vector<std::unique_ptr<IButton>> buttons;std::vector<std::unique_ptr<ITextBox>> textBoxes;std::vector<std::unique_ptr<ICheckBox>> checkBoxes;public:explicit Application(std::unique_ptr<IUIFactory> uiFactory) : factory(std::move(uiFactory)) {}void createUI() {std::cout << "🎨 使用 " << factory->getFactoryName() << " 创建UI..." << std::endl;// 创建按钮buttons.push_back(factory->createButton("确认"));buttons.push_back(factory->createButton("取消"));buttons.push_back(factory->createButton("帮助"));// 创建文本框textBoxes.push_back(factory->createTextBox());// 创建复选框checkBoxes.push_back(factory->createCheckBox("记住密码", true));checkBoxes.push_back(factory->createCheckBox("自动登录", false));}void renderUI() const {std::cout << "\n🌈 渲染UI组件:" << std::endl;std::cout << "==========================================" << std::endl;for (const auto& button : buttons) {button->render();}std::cout << std::endl;for (const auto& textBox : textBoxes) {textBox->render();}std::cout << std::endl;for (const auto& checkBox : checkBoxes) {checkBox->render();}std::cout << "==========================================" << std::endl;}void simulateUserInteraction() {std::cout << "\n🎭 模拟用户交互:" << std::endl;if (!buttons.empty()) buttons[0]->onClick();if (!textBoxes.empty()) {textBoxes[0]->onInput("Hello, World! 这是一个测试文本");textBoxes[0]->render();}if (!checkBoxes.empty()) {checkBoxes[0]->onToggle(false);checkBoxes[0]->render();}}void showComponentDescriptions() const {std::cout << "\n📋 组件描述:" << std::endl;for (const auto& button : buttons) {std::cout << "   • " << button->getDescription() << std::endl;}for (const auto& textBox : textBoxes) {std::cout << "   • " << textBox->getDescription() << std::endl;}for (const auto& checkBox : checkBoxes) {std::cout << "   • " << checkBox->getDescription() << std::endl;}}
};// ==================== 工厂创建器 ====================
class UIFactoryCreator {
public:static std::unique_ptr<IUIFactory> createFactory(const std::string& osType) {if (osType == "Windows") {return std::make_unique<WindowsUIFactory>();} else if (osType == "Mac") {return std::make_unique<MacUIFactory>();} else {throw std::runtime_error("不支持的操作系统类型: " + osType);}}static std::unique_ptr<IUIFactory> createFactoryForCurrentOS() {
#if defined(_WIN32) || defined(_WIN64)return std::make_unique<WindowsUIFactory>();
#elif defined(__APPLE__)return std::make_unique<MacUIFactory>();
#elsethrow std::runtime_error("无法检测当前操作系统");
#endif}
};// ==================== 主函数 ====================
int main() {std::cout << "🚀 抽象工厂模式演示 - 跨平台UI组件库" << std::endl;std::cout << "==========================================" << std::endl;try {// 方式1: 根据当前操作系统自动选择std::cout << "\n1. 自动检测操作系统创建工厂..." << std::endl;auto autoFactory = UIFactoryCreator::createFactoryForCurrentOS();Application app1(std::move(autoFactory));app1.createUI();app1.renderUI();app1.simulateUserInteraction();app1.showComponentDescriptions();// 方式2: 手动指定操作系统std::cout << "\n\n2. 手动指定创建Windows工厂..." << std::endl;auto winFactory = UIFactoryCreator::createFactory("Windows");Application app2(std::move(winFactory));app2.createUI();app2.renderUI();app2.showComponentDescriptions();std::cout << "\n\n3. 手动指定创建Mac工厂..." << std::endl;auto macFactory = UIFactoryCreator::createFactory("Mac");Application app3(std::move(macFactory));app3.createUI();app3.renderUI();app3.showComponentDescriptions();} catch (const std::exception& e) {std::cerr << "❌ 错误: " << e.what() << std::endl;return 1;}std::cout << "\n🎉 演示完成!" << std::endl;return 0;
}

3.2 Makefile 编译文件

# Makefile for Abstract Factory Demo
CXX = g++
CXXFLAGS = -std=c++14 -Wall -Wextra -O2
TARGET = ui_demo
SOURCES = main.cpp# 检测操作系统
UNAME_S := $(shell uname -s)# 设置平台相关标志
ifeq ($(UNAME_S),Linux)CXXFLAGS += -DLINUX
endif
ifeq ($(UNAME_S),Darwin)CXXFLAGS += -DMACOS
endif
ifeq ($(OS),Windows_NT)CXXFLAGS += -DWINDOWS
endif$(TARGET): $(SOURCES)$(CXX) $(CXXFLAGS) -o $(TARGET) $(SOURCES)run: $(TARGET)./$(TARGET)clean:rm -f $(TARGET) *.o.PHONY: run clean

3.3 编译和运行

# 编译程序
make# 运行程序
make run# 或者直接运行
./ui_demo

3.4 预期输出示例

🚀 抽象工厂模式演示 - 跨平台UI组件库
==========================================1. 自动检测操作系统创建工厂...
🎨 使用 Windows UI Factory 创建UI...🌈 渲染UI组件:
==========================================
🪟 渲染Windows风格按钮: 确认┌─────────────────┐│     确认        │└─────────────────┘
🪟 渲染Windows风格按钮: 取消┌─────────────────┐│     取消        │└─────────────────┘
🪟 渲染Windows风格按钮: 帮助┌─────────────────┐│     帮助        │└─────────────────┘🪟 渲染Windows风格文本框:┌─────────────────────────────────┐│ 请输入文本...                  │└─────────────────────────────────┘🪟 渲染Windows风格复选框: 记住密码[✓] 记住密码
🪟 渲染Windows风格复选框: 自动登录[ ] 自动登录
==========================================🎭 模拟用户交互:
💻 Windows按钮被点击: 确认
⌨️  Windows文本框输入: Hello, World! 这是一个测试文本
🪟 渲染Windows风格文本框:┌─────────────────────────────────┐│ Hello, World! 这是一个测试文本 │└─────────────────────────────────┘
✅ Windows复选框取消: 记住密码
🪟 渲染Windows风格复选框: 记住密码[ ] 记住密码📋 组件描述:• Windows风格按钮 - 确认• Windows风格按钮 - 取消• Windows风格按钮 - 帮助• Windows风格文本框 - 内容: Hello, Worl...• Windows风格复选框 - 记住密码 : 未选中• Windows风格复选框 - 自动登录 : 未选中

4. 交互性内容解析

4.1 抽象工厂模式的时序图

客户端工厂创建器抽象工厂具体工厂抽象产品具体产品请求创建工厂创建具体工厂返回具体工厂createProductA()new ProductA()返回具体产品返回抽象产品接口createProductB()new ProductB()返回具体产品返回抽象产品接口使用产品方法()返回结果客户端工厂创建器抽象工厂具体工厂抽象产品具体产品

4.2 交互流程详解

  1. 工厂创建阶段:客户端通过工厂创建器获取具体工厂实例
  2. 产品创建阶段:客户端通过具体工厂创建各种产品
  3. 产品使用阶段:客户端通过抽象接口使用产品,不依赖具体实现
  4. 资源清理阶段:智能指针自动管理资源释放

这种交互方式确保了:

  • 客户端与具体实现解耦
  • 产品族内产品兼容性
  • 资源安全管理
  • 易于扩展新的产品族

5. 高级主题与最佳实践

5.1 使用现代C++特性

智能指针管理资源
// 使用unique_ptr确保资源安全
class ModernUIFactory {
public:virtual std::unique_ptr<IButton> createButton() = 0;virtual std::unique_ptr<ITextBox> createTextBox() = 0;
};// 客户端使用
void createUI(std::unique_ptr<ModernUIFactory> factory) {auto button = factory->createButton();auto textBox = factory->createTextBox();// 不需要手动delete,智能指针自动管理
}
使用enum class替代字符串
enum class Platform { Windows, Mac, Linux };class PlatformFactory {
public:static std::unique_ptr<IUIFactory> create(Platform platform) {switch (platform) {case Platform::Windows: return std::make_unique<WindowsUIFactory>();case Platform::Mac: return std::make_unique<MacUIFactory>();case Platform::Linux: return std::make_unique<LinuxUIFactory>();default: throw std::invalid_argument("Unknown platform");}}
};

5.2 处理扩展性问题

解决方案1:使用注册表模式
class FactoryRegistry {
private:std::unordered_map<std::string, std::function<std::unique_ptr<IUIFactory>()>> registry;public:void registerFactory(const std::string& name, std::function<std::unique_ptr<IUIFactory>()> creator) {registry[name] = std::move(creator);}std::unique_ptr<IUIFactory> createFactory(const std::string& name) const {auto it = registry.find(name);if (it != registry.end()) {return it->second();}throw std::runtime_error("Factory not registered: " + name);}static FactoryRegistry& getInstance() {static FactoryRegistry instance;return instance;}
};// 注册工厂
void registerFactories() {auto& registry = FactoryRegistry::getInstance();registry.registerFactory("Windows", []() { return std::make_unique<WindowsUIFactory>(); });registry.registerFactory("Mac", []() { return std::make_unique<MacUIFactory>(); });
}
解决方案2:使用反射机制(C++17及以上)
#include <type_traits>template<typename T>
concept UIFactory = std::is_base_of_v<IUIFactory, T>;class ReflexiveFactory {
public:template<UIFactory T>static std::unique_ptr<IUIFactory> create() {return std::make_unique<T>();}
};// 使用
auto factory = ReflexiveFactory::create<WindowsUIFactory>();

5.3 性能优化考虑

对象池模式

对于创建成本高的对象,可以使用对象池:

class ButtonPool {
private:std::vector<std::unique_ptr<IButton>> pool;std::function<std::unique_ptr<IButton>()> creator;public:explicit ButtonPool(std::function<std::unique_ptr<IButton>()> btnCreator) : creator(std::move(btnCreator)) {}std::unique_ptr<IButton> acquire() {if (pool.empty()) {return creator();}auto button = std::move(pool.back());pool.pop_back();return button;}void release(std::unique_ptr<IButton> button) {pool.push_back(std::move(button));}
};

6. 总结

抽象工厂模式是一个极其强大的创建型设计模式,它解决了创建相关对象家族的问题,同时保持了客户端代码与具体实现的解耦

核心价值

  1. 产品兼容性保证:确保创建的对象能够协同工作
  2. 客户端代码简洁:客户端只依赖抽象接口,不关心具体实现
  3. 易于切换产品族:通过更换工厂即可切换整套产品
  4. 符合开闭原则:新增产品族无需修改现有代码

适用场景

  • 系统需要支持多个产品家族
  • 产品家族中的产品需要一起使用
  • 需要提供产品的类库,只暴露接口不暴露实现
  • 强调一系列相关产品对象的设计约束

注意事项

  1. 扩展产品种类困难:增加新产品需要修改所有工厂接口
  2. 增加了系统复杂度:引入了大量的接口和类
  3. 可能创建不必要的对象:如果不需要整套产品,可能会创建多余对象

现代C++最佳实践

  1. 使用智能指针管理资源生命周期
  2. 使用enum class提高类型安全性
  3. 结合工厂注册表提高扩展性
  4. 考虑性能优化如对象池模式

抽象工厂模式是构建大型、可维护、可扩展系统的强大工具,正确使用它可以显著提高代码质量和开发效率。


文章转载自:

http://gsoVH2Gh.ykrss.cn
http://hECnnWo1.ykrss.cn
http://dWERd50T.ykrss.cn
http://5oe7k8bJ.ykrss.cn
http://2gzZFUym.ykrss.cn
http://h3qFSSaf.ykrss.cn
http://OHiV2sAk.ykrss.cn
http://xU5Bysjk.ykrss.cn
http://THXQpnRy.ykrss.cn
http://IX3HdYMg.ykrss.cn
http://r3hscgKK.ykrss.cn
http://oaBtOCV5.ykrss.cn
http://mispB6lm.ykrss.cn
http://6r3wytdo.ykrss.cn
http://eEF4bVgs.ykrss.cn
http://wUurzzP2.ykrss.cn
http://7u2LYK7k.ykrss.cn
http://7XzdsEfp.ykrss.cn
http://kxhNFcBm.ykrss.cn
http://XhavKVA3.ykrss.cn
http://kIyZacef.ykrss.cn
http://gsArqzpP.ykrss.cn
http://ycEuBRq4.ykrss.cn
http://aXqmjnWv.ykrss.cn
http://5StFwC7P.ykrss.cn
http://TkbsJpOK.ykrss.cn
http://g3A5tPlX.ykrss.cn
http://jSc3KqWQ.ykrss.cn
http://pNOfrEkD.ykrss.cn
http://7g2WbhQ0.ykrss.cn
http://www.dtcms.com/a/379947.html

相关文章:

  • Vivado SDK 中 XScuGic(ARM Cortex-A9 SCU GIC 中断控制器)相关函数
  • 【学习K230-例程21】GT6700-UDP-Client
  • 考研408计算机网络近年第34题真题解析(2021-2024.34)
  • 安装vcenter6.7 第二阶段安装很慢 或卡在50%
  • 《赛事报名系统小程序》
  • 倍福PLC常见问题
  • 课前准备--解析空间转录组肿瘤微环境SNV(visium、stereo)
  • Linux下C语言实现HTTP+SQLite3电子元器件查询系统
  • 第四节 JavaScript——深入变量、作用域与内存管理
  • 淘客返利app后端系统架构设计:从数据一致性到高可用方案
  • 自动清除ROS日志方法汇总
  • GitHub 上整合深度学习 + 遥感数据集(或工具库/benchmark)的项目
  • 学习日记-JS+DOM-day54-9.12
  • 数据分析毕业论文题目推荐:精选选题清单
  • Apache Flink 从流处理基础到恰好一次语义
  • 第2篇:数据持久化实战
  • redis sentinel 与 clauster 的区别
  • Vue: 侦听器(Watch)
  • HTML 设计与使用入门
  • 【大数据专栏】流式处理框架-Apache Fink
  • 老项目CSS样式失效?调整css插件版本解决
  • Flink 实时流处理实战:电商实时大屏分析
  • ARM(7)IMX6ULL 按键控制(轮询 + 中断)优化工程
  • 基于STM32设计的青少年学习监控系统(华为云IOT)_282
  • Django全栈班v1.04 Python基础语法 20250912 上午
  • Vue3+ts使用oidc-client-ts
  • V少JS基础班之第八弹
  • webrtc弱网-AlrDetector类源码分析与算法原理
  • 鸿蒙Next Web渲染与布局详解:深入理解自适应布局与渲染模式
  • 猿辅导前端面试题及参考答案