不得不说的创建型模式-抽象工厂模式

news2024/11/18 7:50:01

抽象工厂模式是一种创建型模式,它提供一个接口来创建一系列相关或相互依赖的对象,而不需要指定它们的具体类。这个接口被称为“抽象工厂”,它可以被不同的具体工厂实现来创建不同的产品族。

下面通过一个简单的示例来说明抽象工厂模式的底层原理和实际应用。

示例场景: 假设我们需要设计一个跨平台的图形用户界面(GUI)库,它需要支持Windows和Linux两个操作系统,同时还需要支持不同的界面主题(如浅色和深色主题)。为了支持不同的操作系统和主题,我们需要使用抽象工厂模式。

首先定义抽象工厂接口:

class AbstractGUIFactory {
public:
    virtual Button* createButton() = 0;
    virtual TextBox* createTextBox() = 0;
    virtual Label* createLabel() = 0;
};

然后定义具体工厂类来实现这个接口:

class WindowsGUIFactory : public AbstractGUIFactory {
public:
    Button* createButton() { return new WindowsButton(); }
    TextBox* createTextBox() { return new WindowsTextBox(); }
    Label* createLabel() { return new WindowsLabel(); }
};

class LinuxGUIFactory : public AbstractGUIFactory {
public:
    Button* createButton() { return new LinuxButton(); }
    TextBox* createTextBox() { return new LinuxTextBox(); }
    Label* createLabel() { return new LinuxLabel(); }
};

接下来定义产品类:

class Button {
public:
    virtual void paint() = 0;
};

class TextBox {
public:
    virtual void display() = 0;
};

class Label {
public:
    virtual void draw() = 0;
};

最后定义具体产品类来实现这些产品接口:

class WindowsButton : public Button {
public:
    void paint() {
        // Windows风格的按钮绘制逻辑
    }
};

class LinuxButton : public Button {
public:
    void paint() {
        // Linux风格的按钮绘制逻辑
    }
};

class WindowsTextBox : public TextBox {
public:
    void display() {
        // Windows风格的文本框绘制逻辑
    }
};

class LinuxTextBox : public TextBox {
public:
    void display() {
        // Linux风格的文本框绘制逻辑
    }
};

class WindowsLabel : public Label {
public:
    void draw() {
        // Windows风格的标签绘制逻辑
    }
};

class LinuxLabel : public Label {
public:
    void draw() {
        // Linux风格的标签绘制逻辑
    }
};

这样,我们就可以通过不同的具体工厂类来创建不同的产品族,比如使用WindowsGUIFactory来创建Windows风格的GUI,使用LinuxGUIFactory来创建Linux风格的GUI。在不同的操作系统和主题下,我们只需要改变具体工厂类的实现即可,而不需要修改已有的代码。

抽象工厂模式的主要优点是:

  1. 保证了产品族内部的一致性。由于抽象工厂只负责创建一系列相关的产品,因此它可以确保这些产品之间的兼容性和一致性。

  2. 使得切换产品族变得容易。由于具体工厂类实现了抽象工厂接口,因此我们可以通过切换具体工厂类来创建不同的产品族,从而使得切换产品族变得容易。

  3. 使得扩展产品族变得容易。如果需要添加新的产品族,只需要添加一个新的具体工厂类和一些新的产品类即可,而不需要修改已有的代码。

抽象工厂模式的主要缺点是:

  1. 不够灵活。由于抽象工厂只负责创建一系列相关的产品,因此在需要创建新的产品时,可能需要修改抽象工厂的接口和所有的具体工厂类,这样会导致系统变得不够灵活。

  2. 不够扩展。如果需要添加新的产品族或者新的产品等级结构,可能需要修改抽象工厂的接口和所有的具体工厂类,这样会导致系统变得不够扩展。

抽象工厂模式在GUI库、游戏引擎等需要创建一系列相关的产品的场景下得到了广泛的应用。在这些场景下,我们需要根据不同的操作系统、不同的设备和不同的用户需求来创建不同的产品,而抽象工厂模式提供了一种很好的解决方案。

具体来说,抽象工厂模式可以应用于以下场景:

  1. 操作系统界面:不同的操作系统有不同的用户界面,例如Windows和Mac OS X,它们的用户界面是不同的,因此我们可以使用抽象工厂模式来创建不同操作系统的用户界面。

  2. 游戏引擎:游戏引擎中需要创建很多不同的对象,例如纹理、音效、粒子效果等,而这些对象又需要根据不同的平台进行优化和适配,因此我们可以使用抽象工厂模式来创建不同平台下的游戏对象。

  3. 数据库访问:不同的数据库有不同的访问方式,例如MySQL和Oracle,它们的访问方式是不同的,因此我们可以使用抽象工厂模式来创建不同的数据库访问对象。

总之,抽象工厂模式提供了一种很好的解决方案,可以帮助我们创建一系列相关的产品,并确保这些产品之间的兼容性和一致性。但是,它也有一些缺点,可能会导致系统变得不够灵活和不够扩展,因此在应用抽象工厂模式时需要权衡利弊,选择合适的设计模式。

假设我们正在开发一个游戏,这个游戏需要支持不同的平台,例如Windows、Linux和Mac OS X,同时还需要支持不同的分辨率和不同的语言。为了实现这个功能,我们可以使用抽象工厂模式来创建不同平台下的游戏对象,例如游戏画面、音效、输入设备等。具体实现如下:

首先,我们需要定义抽象工厂接口,该接口包含了创建游戏对象的方法,例如创建游戏画面、音效和输入设备等:

class AbstractFactory {
public:
    virtual std::shared_ptr<GameScreen> CreateGameScreen() = 0;
    virtual std::shared_ptr<GameAudio> CreateGameAudio() = 0;
    virtual std::shared_ptr<GameInput> CreateGameInput() = 0;
};

然后,我们需要定义具体的工厂类,例如WindowsFactory、LinuxFactory和MacFactory,这些工厂类都实现了抽象工厂接口,并且分别创建了Windows、Linux和Mac OS X下的游戏对象:

class WindowsFactory : public AbstractFactory {
public:
    virtual std::shared_ptr<GameScreen> CreateGameScreen() override {
        return std::make_shared<WindowsGameScreen>();
    }

    virtual std::shared_ptr<GameAudio> CreateGameAudio() override {
        return std::make_shared<WindowsGameAudio>();
    }

    virtual std::shared_ptr<GameInput> CreateGameInput() override {
        return std::make_shared<WindowsGameInput>();
    }
};

class LinuxFactory : public AbstractFactory {
public:
    virtual std::shared_ptr<GameScreen> CreateGameScreen() override {
        return std::make_shared<LinuxGameScreen>();
    }

    virtual std::shared_ptr<GameAudio> CreateGameAudio() override {
        return std::make_shared<LinuxGameAudio>();
    }

    virtual std::shared_ptr<GameInput> CreateGameInput() override {
        return std::make_shared<LinuxGameInput>();
    }
};

class MacFactory : public AbstractFactory {
public:
    virtual std::shared_ptr<GameScreen> CreateGameScreen() override {
        return std::make_shared<MacGameScreen>();
    }

    virtual std::shared_ptr<GameAudio> CreateGameAudio() override {
        return std::make_shared<MacGameAudio>();
    }

    virtual std::shared_ptr<GameInput> CreateGameInput() override {
        return std::make_shared<MacGameInput>();
    }
};

最后,我们可以在游戏中使用具体工厂类来创建不同平台下的游戏对象,例如:

void Game::Init(const std::string& platform, int resolution, const std::string& language) {
    std::shared_ptr<AbstractFactory> factory;

    if (platform == "Windows") {
        factory = std::make_shared<WindowsFactory>();
    }
    else if (platform == "Linux") {
        factory = std::make_shared<LinuxFactory>();
    }
    else if (platform == "Mac OS X") {
        factory = std::make_shared<MacFactory>();
    }
    else {
        throw std::runtime_error("Unsupported platform");
    }

    m_gameScreen = factory->CreateGameScreen();
    m_gameAudio = factory->CreateGameAudio();
    m


上述代码中,我们通过传递平台、分辨率和语言等参数来创建不同平台下的游戏对象。具体来说,我们先根据平台类型创建相应的工厂对象,然后使用工厂对象来创建游戏对象,最后设置游戏对象的参数。通过这种方式,我们可以在游戏运行时根据需要动态地创建不同平台下的游戏对象,从而实现游戏的跨平台支持。

抽象工厂模式在实际应用中具有广泛的应用。例如,操作系统中的GUI工具包就是一个典型的抽象工厂模式的应用,不同的操作系统下使用不同的GUI工具包,而不同的GUI工具包又可以支持不同的控件和主题等。此外,在游戏开发、网络编程、图形图像处理等领域中,抽象工厂模式也有着重要的应用。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/441959.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[API]string常量池string常用方法StringBuilder类(一)

String字符串类型&#xff1a; java.lang.String类使用final修饰&#xff0c;不能被继承 String的底层封装的是一个字符数组 String在内存中采用Unicode编码格式&#xff0c;每个字符占用2个字节的内存空间 字符串对象一旦创建&#xff0c;对象内容永远无法改变&#xff0c;…

Python爬虫实战——下载小说

Python爬虫实战——下载小说 前言第三方库的安装示例代码效果演示结尾 前言 使用requests库下载开源网站的小说 注意&#xff1a;本文仅用于学习交流&#xff0c;禁止用于盈利或侵权行为。 操作系统&#xff1a;windows10 家庭版 开发环境&#xff1a;Pycharm Conmunity 202…

Node【NPM】

文章目录 &#x1f31f;前言&#x1f31f;NPM使用&#x1f31f;NPM使用场景&#x1f31f;NPM的常用命令&#x1f31f;NPM命令使用介绍&#x1f31f; 使用NPM安装模块&#x1f31f; 下载三方包&#x1f31f; 全局安装VS本地安装&#x1f31f; 本地安装&#x1f31f; 全局安装&am…

Vue全家桶

作为后端对vue学习完的快速总结 目录 1.vue-cli 2 vuex 3 axios 4 router vue-cli vue-cli 3 是基于webpack 4 打造的vue-cli 2 还是 webpack 3webpack是基于node.js的&#xff0c;所以我们在安装脚手架前必须安装node 安装node.js(应用商店或者官网) 1.安装vue脚手架 npm…

Storm proxies动态代理IP抓取产品信息用什么类型的代理呢?

抓取产品信息时&#xff0c;可以根据实际需求和目标网站的反爬虫策略选择合适的代理类型。以下是一些常见的代理类型&#xff1a; HTTP代理&#xff1a;HTTP代理是最常见的代理类型&#xff0c;适用于基于HTTP协议的网站。它可以用于发送HTTP请求和接收HTTP响应&#xff0c;适合…

storm proxies动态HTTP代理IP的三大功能?

动态HTTP代理IP主要具有以下三大功能&#xff1a; 隐私保护&#xff1a;动态HTTP代理IP可以隐藏用户的真实IP地址&#xff0c;将用户的请求发送到目标网站时&#xff0c;目标网站只能看到代理IP地址&#xff0c;而无法知道用户的真实IP地址&#xff0c;从而保护用户的隐私和身份…

665. 非递减数列

给你一个长度为 n 的整数数组 nums &#xff0c;请你判断在 最多 改变 1 个元素的情况下&#xff0c;该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的&#xff1a; 对于数组中任意的 i (0 < i < n-2)&#xff0c;总满足 nums[i] < nums[i 1]。 示例…

第四章(1):词向量定义与意义

第四章&#xff08;1&#xff09;&#xff1a;词向量定义与意义 目录 第四章&#xff08;1&#xff09;&#xff1a;词向量定义与意义前言1. 词的表示1.1 离散表示1.1.1 One-Hot独热编码1.1.2 ngram特征表示 1.2 分布式表示 2. 意义 前言 在自然语言处理的领域中&#xff0c;每…

电容-基础知识

1、电容两端电压 不能激变&#xff0c;所以可以起到稳定电压作用 2、电容的种类&#xff1a;瓷片电容、插件电解电容、贴片电解电容、钽电容、CBB电容、插件瓷片电容、&#xff08;X电容、Y电容&#xff0c;属于安规电容&#xff0c;对功能没有影响&#xff0c;对性能没有影响…

权限控制_SpringSecurity

认证-授权 认证&#xff1a;系统提供的用于识别用户身份的功能&#xff0c;通常提供用户名和密码进行登录其实就是在进行认证&#xff0c;认证的目的是让系统知道你是谁。 授权&#xff1a;用户认证成功后&#xff0c;需要为用户授权&#xff0c;其实就是指定当前用户可以操作…

【Qt】随记1:#if 1/0 #else #endif的用法

欢迎阅读本博文&#xff0c;本文主要记录Qt学习、工作中的一些注意点及相关笔记&#x1f4c3; 希望记录的内容有帮助到你&#xff0c;也欢迎把你知道的分享给大家&#xff0c;一起进步&#xff01;&#x1f389; 喜欢的话&#xff0c;请帮忙点赞&#x1f44d;、评论&#x1f4…

【排序】快速排序(递归和非递归)

快速排序 前言图解大致思路对于hoare版本对于挖坑法对于前后指针法 实现方法递归非递归 快排的优化&#xff08;基于递归的优化&#xff09;三数取中法小区间优化 时间复杂度和空间复杂度 前言 快速排序&#xff0c;听名字就比较霸道&#xff0c;效率根名字一样&#xff0c;非…

winForm登录页面知识点

先看界面 引用知识 控件&#xff1a;label,Textbox,button还有各自的属性和事件Trim()方法的使用&#xff0c;IsNullOrEmpty()方法的使用&#xff0c;Show()方法的使用 Label 属性 NameText:设置或获取文本信息image:显示图像ImageList:图像集控件SizeTag:与控件相关的自定…

Gorm的关联模型

Belongs To 将一个模型与另一个模型建立一对一的关系 例如&#xff1a;一张银行卡只能分配给一个用户&#xff0c;在User结构体里面创建一个CreditCardId外键关系&#xff0c;然后在User结构体里面嵌套一个CreditCard结构体 // Belongs To // 用户 type User struct {gorm.M…

十个超级好用的Javascript技巧

概览&#xff1a;在实际的开发工作过程中&#xff0c;积累了一些常见又超级好用的Javascript技巧和代码片段&#xff0c;包括整理的其他大神的JS使用技巧&#xff0c;今天筛选了10个&#xff0c;以供大家参考。 动态加载JS文件 在一些特殊的场景下&#xff0c;特别是一些库和…

自己动手做chatgpt:解析gpt底层模型transformer的输入处理

前面我们完成了一些基本概念&#xff0c;如果你对深度学习的基本原理还不了解&#xff0c;你可以通过这里获得更多信息&#xff0c;由于深度学习的教程汗牛充栋&#xff0c;因此我在这里不会重复&#xff0c;而是集中精力到chatgpt模型原理的分析&#xff0c;实现和实践上。Cha…

初识C语言————3

博主这篇文章浅谈一下自己对函数和数组的理解。之后会详细说明。 文章目录 一、函数 二、数组 1、数组定义 2、数组的下标 3、数组的使用 一、函数 函数可以理解为一个模块的代码&#xff0c;完成一个独立的功能。 #include <stdio.h> int main() {int num1 0;int num…

ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7

编辑&#xff1a;ll ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7 型号&#xff1a;ADM3051CRZ-REEL7 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;SOIC-8 批号&#xff1a;2023 引脚数量&#xff1a;8 安装类型&#xff1a;表面贴装型 ADM3051CRZ-REEL7汽…

【Python】读取rdata类型数据转为csv excel格式文件, 无需安装r语言基于pyreadr+pandas实现数据分析(保姆级注释)

目录 环境配置取得数据名 datas.keys()取得pandas的DataFrame类型数据一些数据分析例程供入门同学学习转化为csv excel格式所有数据 转化为csv取前面100行数据 快速测试能否转化csv取前面100行数据 快速测试能否转化xlsx 完整例程总结 欢迎关注 『Python』 系列&#xff0c;持续…

简述AutoGPT原理(提示词)

启动时需要设置三个项目&#xff1a;机器人名字、设定给机器人的角色、要完成的目标。 根据你的设定利用ChatGPT进行下一步的抉择&#xff0c;具体的&#xff0c;实际上归功于提示词&#xff1a; 下面这段提示词在干什么呢&#xff1f; 将设定的名字、角色、目标告诉ChatGPT&…