C++|设计模式(三)|抽象工厂模式

抽象工厂模式仍然属于创建型模式,我们在【简单工厂和工厂方法模式】这篇文章中,描述了简单工厂和工厂方法模式,并在文末,简单介绍了工厂方法模式的局限性。

本文将通过汽车工厂的例子继续来阐述使用抽象工厂模式相比较于工厂方法模式的优势。

文章目录

  • 工厂方法模式回顾
  • 抽象工厂模式
    • 代码使用
    • 抽象工厂的局限性

工厂方法模式回顾

工厂方法模式通过允许类将实例化延迟到子类中来实现,使得增加新的产品类不需要修改现有系统的代码。例如,一个汽车制造商需要不同类型的汽车,如宝马、奥迪等,每种汽车的制造过程可能不同:

#include <iostream>
#include <string>
#include <memory>
using namespace std;class Car {
public:Car(string name) : name_(name) { }virtual ~Car(){}virtual void show() = 0;
protected:string name_;
};class Bmw : public Car {
public:Bmw(string name) : Car(name) { }void show() { cout << "获得一辆宝马汽车 " << name_ <<endl; }
};class Audi : public Car {
public:Audi(string name) : Car(name) { }void show() { cout << "获得一辆奥迪汽车 " << name_ << endl; }
};//工厂方法
class Factory {
public:virtual ~Factory() {}virtual Car* createCar(string name) = 0; //工厂方法
};//宝马工厂
class BMWFactory : public Factory {
public:Car* createCar(string name) { return new Bmw(name); }
};
//奥迪工厂
class AudiFactory : public Factory {
public:Car* createCar(string name) { return new Audi(name); }
};int main () {unique_ptr<Factory> bmwFactory(new BMWFactory());unique_ptr<Factory> audiFactory(new AudiFactory());unique_ptr<Car> p1(bmwFactory->createCar("X6"));unique_ptr<Car> p2(audiFactory->createCar("A8"));p1->show();p2->show();return 0;
}

现在,我们考虑这样一种情况,如果我们现在要生产的产品是一组有关联的产品簇怎么办?难道我们像工厂方法一样,又新建立一个工厂来生产该产品吗?

比如说,我们之前有了奥迪工厂和宝马工厂,现在我们需要生产奥迪车灯和宝马车灯,难道又建立奥迪车灯工厂吗?

这样的话,最后我们需要管理的工厂(类)那也太多了,所以,很容易想到:

我们应该对一组有关联关系的产品簇提供产品对象的统一创建。这就是抽象工厂模式。

抽象工厂模式

我们把之前的工厂方法类写成抽象工厂类,并且里面提供创建车灯的方法,

并且,我们直接在宝马工厂和奥迪工厂去创建车灯:

//系列产品一:汽车
class Car {
public:Car(string name) : name_(name) { }virtual ~Car(){}virtual void show() = 0;
protected:string name_;
};
class Bmw : public Car {
public:Bmw(string name) : Car(name) { }void show() { cout << "获得一辆宝马汽车 " << name_ <<endl; }
};
class Audi : public Car {
public:Audi(string name) : Car(name) { }void show() { cout << "获得一辆奥迪汽车 " << name_ << endl; }
};
//系列产品二:车灯
class Light {
public:virtual ~Light() {}virtual void show() = 0;
};
class BmwLight : public Light{
public:void show() { cout << "BMW light!" << endl;};
};
class AudiLight : public Light{
public:void show() { cout << "Audi light!" << endl;};
};//工厂方法 =》 抽象工厂(对一组有关联关系的产品簇提供产品对象的统一创建)
class AbstractFactory {
public:virtual ~AbstractFactory() {}virtual Car* createCar(string name) = 0; //工厂方法 创建汽车virtual Light* createLight() = 0; // 工厂方法 创建汽车关联的产品--车灯
};//宝马工厂
class BMWFactory : public AbstractFactory {
public:Car* createCar(string name) { return new Bmw(name); }Light* createLight() {return new BmwLight();}
};
//奥迪工厂
class AudiFactory : public AbstractFactory {
public:Car* createCar(string name) { return new Audi(name); }Light* createLight() {return new AudiLight();}
};

代码使用

int main () {unique_ptr<AbstractFactory> bmwFactory(new BMWFactory());unique_ptr<AbstractFactory> audiFactory(new AudiFactory());unique_ptr<Car> p1(bmwFactory->createCar("X6"));unique_ptr<Car> p2(audiFactory->createCar("A8"));unique_ptr<Light> l1(bmwFactory->createCarLight());unique_ptr<Light> l2(audiFactory->createCarLight());p1->show();l1->show();p2->show();l2->show();return 0;
}

抽象工厂的局限性

我们设想这样一种场景,比如说我们的宝马工厂需要创建一个新的类对象(产品),但是奥迪工厂并不需要,但是如果宝马工厂想要创建该类,
我们也比赛在抽象工厂类中去定义这样一个虚函数,尽管奥迪工厂并不需要创建该类对象,他还是不得不去重写该虚函数。这样是不符合逻辑的。

总结:
简单工厂Simple Factory:
优点:把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象,用户不用自己负责new对象,不用了解对象创建的详细过程
缺点:提供创建对象实例的接口函数不闭合,不能对修改关闭
工厂方法Factory Method:
优点:Fatcory基类,提供了一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品,可以做到不同的产品,在不同的工厂里面创建,能够对现有工厂,以及产品的修改关闭
缺点:实际上,很多产品是有管理关系的,属于一个产品簇,不应该放在不同的工厂里面去创建,这样一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护
抽象工厂Abstract Factory
优点:把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面AbstractFactory类,派生类(具体产品的工厂)应该负责创建该产品簇里面所有的产品。

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

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

相关文章

Linux修炼之路之冯系结构,操作系统

目录 一&#xff1a;冯诺依曼体系结构 1.五大组件 2.存储器存在的意义 3.几个问题 二&#xff1a;操作系统 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 一&#xff1a;冯诺依曼体系结构 我们当代的计算机的基本构成都是由冯诺依曼…

Kubernetes 容器编排

应用程序部署演变 主要有三个演变&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应用程序定义资源使用边界&#xff0c;很难合理地分配计算资源&…

【开源】多语言大型语言模型的革新:百亿参数模型超越千亿参数性能

大型人工智能模型&#xff0c;尤其是那些拥有千亿参数的模型&#xff0c;因其出色的商业应用表现而受到市场的青睐。但是&#xff0c;直接通过API使用这些模型可能会带来数据泄露的风险&#xff0c;尤其是当模型提供商如OpenAI等可能涉及数据隐私问题时。私有部署虽然是一个解决…

PY32F003+RTL8710(AT) 实现获取天气情况

一、RTL8710主要AT指令 1、ATSR&#xff1a;模块重启 2、ATSE1&#xff1a;开启回显 3、ATPW1&#xff1a;station模式 4、ATPNssid,password,,&#xff1a;连接到AP 5、ATPK1&#xff1a;设置自动接收 6、ATPC0,v1.yiketianqi.com,80&#xff1a;与网站建立TCP连接 7、ATPT125…

关于pytorch加载模型报错问题

load_net[“params”] 报keyerror 加载模型后查看对应参数是什么 model2 torch.load(m1_path "xxx.pth") print(model1.keys())若输出如下&#xff1a; 已经有相应参数不需要执行 load_net[“params”]若输出如下 则需要load_net[“params”]

Linux-命令上

at是一次性的任务&#xff0c;crond是循环的定时任务 如果 cron.allow 文件存在&#xff0c;只有在文件中出现其登录名称的用户可以使用 crontab 命令。root 用户的登录名必须出现在 cron.allow 文件中&#xff0c;如果这个文件存在的话。系统管理员可以明确的停止一个用户&am…

3D 生成重建014-Bidiff使用二维和三维先验的双向扩散

3D 生成重建014-Bidiff使用二维和三维先验的双向扩散 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 大多数三维生成研究集中在将二维基础模型向上投影到三维空间中&#xff0c;要么通过最小化二维评分蒸馏采样&#xff08;SDS&#xff09;损失&#xff0c;要么通过对多视图…

判断变量是否为数组的几种方法

1、isArray 方法 isArray() 方法用于判断一个对象是否为数组。如果对象是数组返回 true&#xff0c;否则返回 false。 Array.isArray(arr); // true 1 2、对象原型 通过原型链判断是否具有和数组同一原型链的顶端。 arr.__proto__ Array.prototype; // true 1 3、instanceof…

[数据结构] -- 双向循环链表

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…

一文理清database/sql包的使用场景和宕机查询流程

一文理清database/sql包你可能遇到的问题 那么database/sql包实现了什么功能呢&#xff1f;建立数据库连接检测连接是否能ping通通过连接进行具体的sql查询查询完将连接进行关闭当数据库宕掉重启后再次查询 database/sql包创建的db连接 对于数据库宕掉后重启是否仍然有效&#…

AI绘画工具:创意与技术的完美融合

随着人工智能技术的飞速发展&#xff0c;我们见证了无数领域的革新与变革。其中&#xff0c;AI绘画工具的出现&#xff0c;无疑为艺术界带来了一股清新的风潮。这些工具以其独特的魅力&#xff0c;吸引了无数艺术家和创意人士的目光&#xff0c;成为他们表达自我、探索未知的重…

Compose在xml中使用滑动冲突处理

一、背景 在现有Android项目中使用Compose可能存在滑动冲突问题&#xff0c;例如 SmartRefreshLayoutCoordinatorLayoutComposeView(ComposeView这里又是一个LazyColumn) 二、解决方案 官方介绍&#xff1a;https://developer.android.google.cn/develop/ui/compose/touch-inp…

huggingface 笔记:device_map

1 基本映射方法 设计设备映射时&#xff0c;可以让Accelerate库来处理设备映射的计算通过设置device_map为支持的选项之一&#xff08;"auto"、 "balanced"、 "balanced_low_0"、 "sequential"&#xff09;&#xff1b;或者如果想更精…

golang的context和chan 的使用

1. context 作用 context包的context的接口&#xff0c;主要是控制协程执行上下文的时间&#xff0c;以及取消程序的执行&#xff0c;以及上下文中传递数据等作用&#xff0c;golang中耗时或者需要协同的操作都会见到context的身影。 context有几个常用的方法 1.1 context.B…

用爬山算法解决离散的优化问题

爬山算法&#xff0c;也称为梯度上升算法或局部搜索算法&#xff0c;是一种简单有效的优化算法&#xff0c;常用于解决连续或离散的优化问题。爬山算法的基本思想是从一个随机的初始点开始&#xff0c;通过迭代地向局部最优的方向移动&#xff0c;逐步逼近全局最优解。 爬山算…

git管理Codeup云效平台

HTTPS方式实现Git命令 1.进入项目路径&#xff0c;如 cd demo&#xff0c;与此同时&#xff0c;在Codeup平台创建一个空仓库repo&#xff0c;获取空仓库的https协议地址&#xff0c;例如 https://codeup.aliyun.com/xxxx/xxxx/xxx.git。 2.在demo项目下执行 git init命令初始化…

从反向传播(BP)到BPTT:详细数学推导【原理理解】

从反向传播到BPTT&#xff1a;详细推导与问题解析 在本文中&#xff0c;我们将从反向传播算法开始&#xff0c;详细推导出反向传播通过时间&#xff08;Backpropagation Through Time, BPTT&#xff09;算法。重点讨论BPTT中的梯度消失和梯度爆炸问题&#xff0c;并解释如何解…

采用LoRA方法微调llama3大语言模型

文章目录 前言一、Llama3模型简介1.下载llama3源码到linux服务器2.安装依赖3.测试预训练模型Meta-Llama-3-8B4.测试指令微调模型Meta-Llama3-8B-Instruct5.小结 二、LoRA微调Llama31.引入库2.编写配置文件3.LoRA训练的产物 三、测试新模型效果1.编写配置文件2.运行配置文件&…

QT教程-一,初识QT

目录 一,QT是什么&#xff1f;能够使用它做什么&#xff1f; 二&#xff0c;Qt 能够使用的语言 三&#xff0c;Qt主要用于什么领域&#xff1f; 四&#xff0c;Qt开发的软件 一,QT是什么&#xff1f;能够使用它做什么&#xff1f; Qt是一个跨平台的 C 开发库&#xff0c;主…

全球最高点赞记录,世界点赞第一名是谁?世界点赞第一人名字的由来

世界点赞第一人名字的由来&#xff1a; 起源与概念提出&#xff1a; 二十一世纪东方伟大的思想家哲学家教育家颜廷利教授&#xff0c;一位在中国21世纪早期便以其非凡才华和创新精神著称的学者&#xff0c;早在互联网尚未普及的20世纪90年代&#xff0c;就已经提出了“点赞”的…