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

C++设计模式:抽象工厂模式(风格切换案例)

抽象工厂模式(Abstract Factory)是一种创建型设计模式,其核心思想是:为一组相关或相互依赖的对象提供一个创建接口,而无需指定它们具体的类。简单来说,就是一个工厂可以生产一系列相关的对象。

我们接下来通过逐步拆解、举例说明和详细代码注释来理解这个模式。


1. 什么是抽象工厂模式?

举个简单例子:

想象你是个游戏开发者,需要为游戏开发不同风格的用户界面(UI)。

  • 如果玩家在 Windows 上玩,游戏需要提供 Windows 风格的按钮、文本框。
  • 如果玩家在 Mac 上玩,则需要提供 Mac 风格的按钮、文本框。

这里的问题是:

  • 我们需要根据不同的操作系统来生成一套成对的 UI 组件(按钮 + 文本框)。
  • 不同的 UI 组件风格相互独立,代码却不能依赖具体的组件实现。

解决这个问题的方案就是使用抽象工厂模式。它允许我们将“创建对象”的逻辑与对象的具体实现分离开。


2. 模式的核心要素

抽象工厂模式包含以下几部分:

  1. 抽象工厂:定义创建一系列对象的接口。
  2. 具体工厂:实现创建特定风格对象的工厂。
  3. 抽象产品:定义产品的公共接口(如按钮和文本框的接口)。
  4. 具体产品:特定风格的产品实现。
  5. 客户端:通过抽象工厂创建产品,而不关心具体产品的实现。

下面用代码一步步实现这个设计模式。


3. 详细代码实现与讲解

Step 1: 定义抽象产品

按钮和文本框是两种产品。我们需要定义它们的接口,让不同风格的具体产品实现这些接口。

#include <iostream>
#include <memory> // 用于智能指针

// 抽象产品 A: 按钮
class Button {
public:
    virtual void render() const = 0; // 渲染按钮
    virtual ~Button() = default;     // 虚析构,避免内存泄漏
};

// 抽象产品 B: 文本框
class TextBox {
public:
    virtual void render() const = 0; // 渲染文本框
    virtual ~TextBox() = default;
};

解释:

  • ButtonTextBox 是两个抽象接口,定义了按钮和文本框的行为(render()方法)。
  • 使用抽象类的好处是,客户端代码可以依赖于接口,而不是具体的实现。

Step 2: 定义具体产品

实现两种风格(Windows 和 Mac)的具体按钮和文本框。

// 具体产品 A1: Windows 风格按钮
class WindowsButton : public Button {
public:
    void render() const override {
        std::cout << "Rendering Windows-style Button\n";
    }
};

// 具体产品 B1: Windows 风格文本框
class WindowsTextBox : public TextBox {
public:
    void render() const override {
        std::cout << "Rendering Windows-style TextBox\n";
    }
};

// 具体产品 A2: Mac 风格按钮
class MacButton : public Button {
public:
    void render() const override {
        std::cout << "Rendering Mac-style Button\n";
    }
};

// 具体产品 B2: Mac 风格文本框
class MacTextBox : public TextBox {
public:
    void render() const override {
        std::cout << "Rendering Mac-style TextBox\n";
    }
};

解释:

  • WindowsButtonMacButton 分别实现了 Button 接口。
  • WindowsTextBoxMacTextBox 分别实现了 TextBox 接口。
  • 每个具体类实现了它们特定风格的 render() 方法,输出不同的效果。

Step 3: 定义抽象工厂

工厂负责创建相关产品(按钮 + 文本框)。我们定义一个抽象工厂接口,声明创建按钮和文本框的方法。

// 抽象工厂:定义创建一组产品的方法
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() const = 0;   // 创建按钮
    virtual std::unique_ptr<TextBox> createTextBox() const = 0; // 创建文本框
    virtual ~GUIFactory() = default;
};

解释:

  • GUIFactory 是抽象工厂,定义了创建按钮和文本框的接口。
  • 返回值使用了 std::unique_ptr,可以自动管理对象生命周期,防止内存泄漏。

Step 4: 定义具体工厂

实现两个具体工厂,用于创建 Windows 和 Mac 风格的产品。

// 具体工厂 1: Windows 工厂
class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<WindowsButton>(); // 创建 Windows 按钮
    }

    std::unique_ptr<TextBox> createTextBox() const override {
        return std::make_unique<WindowsTextBox>(); // 创建 Windows 文本框
    }
};

// 具体工厂 2: Mac 工厂
class MacFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<MacButton>(); // 创建 Mac 按钮
    }

    std::unique_ptr<TextBox> createTextBox() const override {
        return std::make_unique<MacTextBox>(); // 创建 Mac 文本框
    }
};

解释:

  • WindowsFactoryMacFactory 分别实现了 GUIFactory,负责生成各自风格的产品。
  • 每个工厂实现了 createButton()createTextBox()

Step 5: 编写客户端代码

客户端通过抽象工厂使用产品,而不关心具体实现。

// 客户端代码:通过工厂创建和使用产品
void renderUI(const GUIFactory& factory) {
    auto button = factory.createButton(); // 创建按钮
    auto textBox = factory.createTextBox(); // 创建文本框

    button->render(); // 渲染按钮
    textBox->render(); // 渲染文本框
}

int main() {
    std::cout << "Windows GUI:\n";
    WindowsFactory windowsFactory;
    renderUI(windowsFactory); // 使用 Windows 工厂

    std::cout << "\nMac GUI:\n";
    MacFactory macFactory;
    renderUI(macFactory); // 使用 Mac 工厂

    return 0;
}

解释:

  • renderUI 是客户端函数,通过 GUIFactory 创建产品。
  • 客户端无需关心具体工厂或产品的实现,只依赖于抽象接口。

4. 输出结果

运行上述代码,将输出以下结果:

Windows GUI:
Rendering Windows-style Button
Rendering Windows-style TextBox

Mac GUI:
Rendering Mac-style Button
Rendering Mac-style TextBox

5. 模式的优缺点

优点
  1. 分离具体类:客户端与具体产品的实现解耦。
  2. 确保产品一致性:某个具体工厂生产的所有产品风格一致。
  3. 易于扩展:可以新增工厂和产品系列,而无需修改客户端代码。
缺点
  1. 增加复杂性:需要定义多组接口和类,代码量较多。
  2. 扩展产品族困难:如果需要新增产品(比如菜单),需要修改所有工厂接口和实现。

总结

抽象工厂模式通过工厂接口屏蔽了具体产品的创建细节,使代码更加灵活和可扩展。它非常适合需要生成一组相关对象不希望客户端代码依赖于具体实现的场景。在实际开发中,抽象工厂模式广泛应用于跨平台工具、插件系统等领域。

完整代码实现

以下是抽象工厂模式的完整实现,并将所有输出改为中文形式,便于理解。

#include <iostream>
#include <memory> // 用于智能指针管理

// 抽象产品 A: 按钮
class Button {
public:
    virtual void render() const = 0; // 渲染按钮(纯虚函数)
    virtual ~Button() = default;     // 虚析构,防止内存泄漏
};

// 抽象产品 B: 文本框
class TextBox {
public:
    virtual void render() const = 0; // 渲染文本框(纯虚函数)
    virtual ~TextBox() = default;
};

// 具体产品 A1: Windows 风格按钮
class WindowsButton : public Button {
public:
    void render() const override {
        std::cout << "渲染 Windows 风格按钮" << "\n"; // 中文输出
    }
};

// 具体产品 B1: Windows 风格文本框
class WindowsTextBox : public TextBox {
public:
    void render() const override {
        std::cout << "渲染 Windows 风格文本框" << "\n"; // 中文输出
    }
};

// 具体产品 A2: Mac 风格按钮
class MacButton : public Button {
public:
    void render() const override {
        std::cout << "渲染 Mac 风格按钮" << "\n"; // 中文输出
    }
};

// 具体产品 B2: Mac 风格文本框
class MacTextBox : public TextBox {
public:
    void render() const override {
        std::cout << "渲染 Mac 风格文本框" << "\n"; // 中文输出
    }
};

// 抽象工厂:定义创建一组产品的方法
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() const = 0;   // 创建按钮
    virtual std::unique_ptr<TextBox> createTextBox() const = 0; // 创建文本框
    virtual ~GUIFactory() = default;
};

// 具体工厂 1: Windows 工厂
class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<WindowsButton>(); // 创建 Windows 按钮
    }

    std::unique_ptr<TextBox> createTextBox() const override {
        return std::make_unique<WindowsTextBox>(); // 创建 Windows 文本框
    }
};

// 具体工厂 2: Mac 工厂
class MacFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<MacButton>(); // 创建 Mac 按钮
    }

    std::unique_ptr<TextBox> createTextBox() const override {
        return std::make_unique<MacTextBox>(); // 创建 Mac 文本框
    }
};

// 客户端代码:通过工厂创建和使用产品
void renderUI(const GUIFactory& factory) {
    // 使用工厂创建按钮和文本框
    auto button = factory.createButton(); // 创建按钮
    auto textBox = factory.createTextBox(); // 创建文本框

    // 渲染创建的产品
    button->render();
    textBox->render();
}

int main() {
    // 使用 Windows 工厂创建产品
    std::cout << "Windows 界面:" << "\n"; // 中文输出
    WindowsFactory windowsFactory;
    renderUI(windowsFactory);

    // 使用 Mac 工厂创建产品
    std::cout << "\nMac 界面:" << "\n"; // 中文输出
    MacFactory macFactory;
    renderUI(macFactory);

    return 0;
}

输出结果

运行该程序,输出如下:

Windows 界面:
渲染 Windows 风格按钮
渲染 Windows 风格文本框

Mac 界面:
渲染 Mac 风格按钮
渲染 Mac 风格文本框

本文由mdnice多平台发布


http://www.kler.cn/a/400694.html

相关文章:

  • 智谱AI清影升级:引领AI视频进入音效新时代
  • 富格林:安全指正规防欺诈套路
  • 【EasyExcel】复杂导出操作-自定义颜色样式等(版本3.1.x)
  • 父组件提交时让各自的子组件验证表格是否填写完整
  • Redis知识分享(三)
  • vue项目使用eslint+prettier管理项目格式化
  • IDEA如何设置编码格式,字符编码,全局编码和项目编码格式
  • 静默绑定推广人方法修复
  • 微信小程序内嵌h5页面(uniapp写的),使用uni.openLocation无法打开页面问题
  • 计算机网络-理论部分(二):应用层
  • django从入门到精通(五)——表单与模型
  • LeetCode 1004.最大连续1的个数III
  • 工程车识别算法平台LiteAIServer算法定制工程车类型检测算法:建筑工地安全管理的得力助手
  • 设备树总结学习
  • Arcgis js 加载mvt服务
  • 驾驭未来:Spring Boot汽车资讯门户
  • 网络协议之Ethernet
  • 3、.Net UI库:CSharpSkin - 开源项目研究文章
  • 算法——反转链表(leetcode206)
  • 数据分析-48-时间序列变点检测之在线实时数据的CPD
  • Go语言24小时极速学习教程(三)常见标准库用法
  • 3-KSQL
  • 【C#设计模式(11)——外观模式(Facade Pattern)】
  • 大数据治理:构建数据价值链的关键环节
  • 安全见闻6-9
  • 机器学习day5-随机森林和线性代数1最小二乘法