03创建型设计模式——抽象工厂模式

一、抽象工厂模式简介

        抽象工厂模式是所有形态的工厂模式中最为抽象和具有一般性的。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。例如现实生活中,水果的种类繁多,众多水果中,桃子也分很多种类,还分地域,比如北方的猕猴桃,南方的猕猴桃等。而抽象工厂模式就是模拟现实中的分类,实现生产一个产品组(相对工厂模式,抽象工厂模式可以生产一个产品的族)。抽象工厂模式的核心思想是定义一个用于创建一系列相关或相互依赖对象的接口,而不需要指定具体类。这种模式的主要优点是它将对象的创建和使用分开,使得系统更具扩展性和灵活性。

产品等级和产品族的关系

工厂模式(具体)和抽象工厂模式(抽象)的对比解释:

具体工厂在开闭原则下, 能生产香蕉/苹果/梨子;  (产品等级结构)

抽象工厂:在开闭原则下, 能生产:南方香蕉/苹果/梨子 (产品族)

北方香蕉/苹果/梨子

GoF一书中对抽象工厂模式的介绍

二、抽象工厂模式的用处

1. 创建相关或相互依赖的对象

抽象工厂模式可以确保客户端只通过工厂接口创建一组相关或相互依赖的对象,而不需要了解具体的对象类。这种方法可以确保这些对象能够一起正常工作。例如,我的代码中,NorthFactory 和 SouthFactory 创建了一系列北方或南方的水果,确保了这些水果的创建和使用是一致的。

2. 提供对象的跨平台支持

当系统需要在不同平台或环境下运行时(如不同操作系统、不同硬件架构等),抽象工厂模式可以提供一个统一的接口来创建对象,从而简化了跨平台的对象创建过程。例如,一个应用程序可以根据不同的操作系统(Windows、Linux、MacOS)选择不同的工厂来创建界面组件。

3. 促进系统的扩展和维护

抽象工厂模式使得系统的扩展变得更加容易。添加新的产品或产品家族时,只需要添加新的工厂类和产品类,而不需要修改现有的客户端代码。这种模式隔离了客户端与具体产品的创建细节,减少了代码的耦合度,从而使系统更容易维护和扩展。

4. 实现产品的一致性

通过将对象的创建过程封装在工厂类中,可以确保创建出的对象具有一致的风格或特点。这在需要保证一组对象之间的兼容性或一致性时尤其重要。例如,我的代码中,不同的工厂保证了北方和南方水果的一致性。

5. 支持不同的产品变种

如果一个系统需要支持多种变种的产品(例如不同风味、不同颜色的产品),抽象工厂模式可以通过不同的工厂实现来支持这些变种。每个工厂可以生成一组产品的不同变种,这样系统可以根据需求选择合适的工厂来获取相应的产品。

三、抽象工厂模式的设计方法

 abstractFactory.cpp

#include <iostream>
#include <cstring>using namespace std;class Fruit
{
public:virtual void getProduct() = 0;virtual ~Fruit() = default;
};class AbstractFactory
{
public:virtual Fruit* CreateProduct(const std::string& type) = 0;virtual ~AbstractFactory() = default;
};class NorthBanana : public Fruit
{
public:void getProduct() override{std::cout << "北方香蕉 " << std::endl;}
};class NorthApple : public Fruit
{
public:void getProduct() override{std::cout << "北方苹果 " << std::endl;}
};class NorthOrange : public Fruit
{
public:void getProduct() override{std::cout << "北方橙子 " << std::endl;}
};class NorthWatermelon : public Fruit
{
public:void getProduct() override{std::cout << "北方西瓜 " << std::endl;}
};class NorthCherry : public Fruit
{
public:void getProduct() override{std::cout << "北方樱桃 " << std::endl;}
};class NorthPeach : public Fruit
{
public:void getProduct() override{std::cout << "北方桃子 " << std::endl;}
};class NorthPear : public Fruit
{
public:void getProduct() override{std::cout << "北方梨 " << std::endl;}
};class SouthBanana : public Fruit
{
public:void getProduct() override{std::cout << "南方香蕉" << std::endl;}
};class SouthApple : public Fruit
{
public:void getProduct() override{std::cout << "南方苹果" << std::endl;}
};class SouthOrange : public Fruit
{
public:void getProduct() override{std::cout << "南方橙子" << std::endl;}
};class SouthWatermelon : public Fruit
{
public:void getProduct() override{std::cout << "南方西瓜" << std::endl;}
};class SouthCherry : public Fruit
{
public:void getProduct() override{std::cout << "南方樱桃" << std::endl;}
};class SouthPeach : public Fruit
{
public:void getProduct() override{std::cout << "南方桃子" << std::endl;}
};class SouthPear : public Fruit
{
public:void getProduct() override{std::cout << "南方梨" << std::endl;}
};class NorthFactory : public AbstractFactory
{Fruit * CreateProduct(const std::string& type) override{if (type == "北方香蕉") return new NorthBanana;if (type == "北方苹果") return new NorthApple;if (type == "北方橙子") return new NorthOrange;if (type == "北方西瓜") return new NorthWatermelon;if (type == "北方樱桃") return new NorthCherry;if (type == "北方桃子") return new NorthPeach;if (type == "北方梨") return new NorthPear;return nullptr;}
};class SouthFactory : public AbstractFactory
{Fruit * CreateProduct(const std::string& type) override{if (type == "南方香蕉") return new SouthBanana;if (type == "南方苹果") return new SouthApple;if (type == "南方橙子") return new SouthOrange;if (type == "南方西瓜") return new SouthWatermelon;if (type == "南方樱桃") return new SouthCherry;if (type == "南方桃子") return new SouthPeach;if (type == "南方梨") return new SouthPear;return nullptr;}
};void doWorking()
{Fruit		*fruit = nullptr;AbstractFactory 	*abstractfactory = nullptr;// 注册南方工厂abstractfactory = new SouthFactory;fruit = abstractfactory->CreateProduct("南方香蕉");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方苹果");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方橙子");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方西瓜");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方樱桃");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方桃子");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("南方梨");if (fruit) { fruit->getProduct(); delete fruit; }// 注销南方工厂delete abstractfactory;// 注册北方工厂abstractfactory = new NorthFactory;fruit = abstractfactory->CreateProduct("北方香蕉");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方苹果");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方橙子");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方西瓜");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方樱桃");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方桃子");if (fruit) { fruit->getProduct(); delete fruit; }fruit = abstractfactory->CreateProduct("北方梨");if (fruit) { fruit->getProduct(); delete fruit; }// 注销北方工厂delete abstractfactory;return ;
}int main(){//开工干活doWorking();return 0;
}

运行效果

  1. 抽象工厂类 (AbstractFactory): 这是一个抽象类,定义了一个抽象方法 CreateProduct,用于创建不同类型的 Fruit 对象。

  2. 具体工厂类 (NorthFactory 和 SouthFactory): 这些类继承自 AbstractFactory,实现了 CreateProduct 方法。它们负责生产具体的 Fruit 对象,如 NorthBananaSouthApple 等。

  3. 抽象产品类 (Fruit): 这是一个抽象基类,定义了一个纯虚方法 getProduct,由具体的产品类实现。

  4. 具体产品类 (NorthBananaSouthApple 等): 这些类继承自 Fruit,实现了 getProduct 方法,代表了具体的水果产品。

  5. 客户端代码 (doWorking 函数): 客户端代码通过抽象工厂接口创建对象,而不关心具体的实现类。它可以轻松地切换工厂(比如从南方工厂切换到北方工厂),而无需修改对象创建的代码。

在代码中,AbstractFactory 提供了创建 Fruit 对象的接口,而 NorthFactory 和 SouthFactory 分别实现了这个接口,创建北方和南方的水果。这样,如果需要添加新的工厂(比如中方工厂)或新的水果类型,只需要在相应的工厂类中添加相应的代码,而不需要修改客户端代码。

 四、总结

抽象工厂模式通过提供一个创建一系列相关对象的接口,解耦了客户端代码和具体产品类,使得系统具有更好的灵活性和扩展性。它广泛应用于各种软件系统中,尤其是需要创建和管理多种相关对象的场景。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3+Ts项目中经常遇到导入组件,vscode报无法找到模块xxx,xxx隐式拥有 “any“ 类型解决办法~

1、报错截图&#xff1a; 2、解决办法&#xff1a;在确保路径正确的情况下&#xff0c;你会在 src 目录下找到一个名为 env.d.ts 的文件&#xff08;或者类似的名称&#xff09;。在这个文件中&#xff0c;你可以声明 .vue 文件的模块类型。例如&#xff1a;(这告诉 TypeScript…

系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

虚拟内存 虚拟内存是一种操作系统提供的机制&#xff0c;用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上。通过使用虚拟内存&#xff0c;操作系统可以有效地解决多个应用程序直接操作物理内存可能引发的冲突问题。 在使用虚拟内存的情况下&#xff0…

IDEA打开持久层的代码很卡,关掉mybatis-plus的插件

不知道大家有没有遇到过打开 mapper 层的页面&#xff0c;然后要切换另外 java 文件的时候很卡&#xff0c;我遇到过卡了好几分钟的&#xff0c;那种继承了 mybatis-plus 的 mapper java文件或者 xml 文件都会&#xff0c;我后来把 mybatis 的插件关掉了&#xff0c;就不会了

LVS的12种调度算法详解

1.lvs调度算法类型 1.1静态方法 仅根据算法本身进行调度&#xff0c;不考虑RS的负载情况 1.2动态方法 主要根据每RS当前的负载状态及调度算法进行调度Overheadvalue较小的RS将被调度 1.1lvs静态调度算法 1.1.1RR&#xff08;轮询算法&#xff09;&#xff1a; roundrobin 轮…

Haproxy状态页

HAProxy 的状态页是一个非常有用的监控和诊断工具&#xff0c;它提供了关于 HAProxy 服务器运行状态的详细信息&#xff0c;通过web界面&#xff0c;显示当前HAProxy的运行状态。 状态页通常包含以下关键信息&#xff1a; 前端&#xff08;Frontend&#xff09;和后端&#x…

从TiDB迁移到OceanBase的实践分享

本文来自OceanBase热心用户的分享 近期&#xff0c;我们计划将业务数据库从TiDB迁移到OceanBase&#xff0c;但面临的一个主要挑战是如何更平滑的完成这一迁移过程。经过研究&#xff0c;了解到OceanBase提供的OMS数据迁移工具能够支持从TiDB到OceanBase的迁移&#xff0c;并且…

js构造函数的prototype赋值总结

我们知道通过构造函数的prototype,可以生成让所有实例对象访问的通用属性和方法,下面通过代码来解释这个过程 function Person(name){this.name name; }Person.prototype.sex man我们定义了一个构造函数Person,然后给它的prototype添加了一个sex的属性,下面我们来看看Person…

OSPF进阶

一、LSA详解 Type&#xff1a;LSA的类型&#xff08;1、2、3、4、5、7类&#xff09; link-state-ID&#xff1a;链路状态表示符 ADV router&#xff1a;产生该LSA的路由器 age&#xff1a;老化时间 Metric&#xff1a;开销值&#xff0c;一般都为ADV router到达该路由的开…

人工智能,代跑通,预测模型,模型优化

人工智能&#xff0c;代跑通&#xff0c;预测模型&#xff0c;模型优化&#xff0c;增加模块&#xff0c;文章复现&#xff0c;python代做&#xff0c;预测&#xff0c;微调&#xff0c;融合&#xff0c;深度学习&#xff0c;机器学习程序代写&#xff0c;环境调试&#xff0c;…

STM32-门电路-储存器-寄存器-STM32f1-MCU-GPIO-总线-keil5-点led-寄存器编程

1、门电路 门电路组成简单加法器&#xff1a; 二进制对电路的影响&#xff1a; 0和1代表无和有&#xff1b; 以下图例&#xff0c;演示与门&#xff1a;左1右1输出1&#xff1b; 电平标准&#xff1a;使用不同的电压表示数字0和1&#xff1b; 高电平&#xff1a;1&#xff1…

攻防世界-web-ctf-upload

题目场景 查看源码 毫无有效的数据 官方WriteUp 本题需要利用文件上传漏洞点&#xff0c;通过绕过服务器的安全防护&#xff0c;达到getshell的目的 本题的主要考点为利用fastcgi的.user.ini特性进行任意命令执行 这里需要绕过的点如下 检查文件内容是否有php字符串 检查…

haproxy七层代理

目录 一、haproxy简介 二、haproxy实验 1.环境部署 2.haproxy的基本部署方法及负载均衡的实现 2.1安装软件 2.2haproxy的基本配置 3.haproxy的全局配置参数及日志分离 3.1多线程设定 3.2自定义日志 4.haproxy-proxies中的常用配置参数 4.1设置backup --- sorryserver…

卷积神经网络(李宏毅老师系列)

自学参考&#xff1a; 一文搞懂卷积神经网络&#xff08;CNN&#xff09;的原理 视频课 课件资料 笔记 一、引入 cnn设计灵感来自于生物学中的视觉系统&#xff0c;旨在模拟人类视觉处理的方式。常用场景&#xff1a;image classification 基本步骤&#xff1a; 把所有图片都先…

数据结构--第六天

--树 -树的基本概念 树结构通常用来储存逻辑关系为“一对多”的数据&#xff0c;例如&#xff1a; 上图的这些元素具有的就是 "一对多" 的逻辑关系&#xff0c;例如元素A同时和B、C、D有关系&#xff0c;元素D同时和A、H、I、J有关系等。 观察这些元素之间的逻辑关…

模拟经营之神:《北境之地》安卓手机游戏,免费分享

《北境之地》&#xff08;Northgard&#xff09;是一款以北欧神话为背景的即时战略游戏&#xff0c;由Shiro Games开发。玩家在游戏中扮演维京部落的领袖&#xff0c;目标是探索新大陆、建立据点、管理资源&#xff0c;并在严酷的冬季和敌人的威胁下生存下来 。 游戏特色包括&a…

gin路由

1主文件 package main import ("github.com/gin-gonic/gin""godade/user""net/http" ) func main() {router : gin.Default()router.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello World")})v1 : router…

如何避免项目发布后用户从浏览器WebPack中看到源码

打包前在config->index.js中设置productionSourceMap为false productionSourceMap: false,

C# AI鉴图宝 利用OCR技术对违规图片进行判别

目录 效果 项目 代码 下载 效果 项目 代码 using Aspose.Cells; using NLog; using OpenCvSharp; using OpenVINO.OCRService; using Sdcb.OpenVINO; using Sdcb.OpenVINO.PaddleOCR; using Sdcb.OpenVINO.PaddleOCR.Models; using System; using System.Collections.Conc…

Jmeter性能压测4000并发

性能测试的底层逻辑 程序为什么会有性能问题 用户操作 客户端&#xff08;web/app/小程序&#xff09;触发网络请求&#xff0c;服务器处理大量网络请求代码运行需要大量服务器资源&#xff08;CPU、内存、网络、磁盘等等&#xff09; 资源不是无限&#xff0c;硬件配置不是随…

使用Python发送PDD直播间弹幕(协议算法分析)

文章目录 1. 写在前面2. 接口分析3. 算法还原 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…