工厂 模式

一、工厂模式是什么?

是C++多态的一种很好的具体表现。通过继承,重写抽象父类的虚函数,并在main函数中通过基类指针指向子类对象的一种编码风格

工厂模式分为三种(简单工厂模式,工厂方法模式,抽象工厂模式)

二、为什么要使用工厂模式?

参考原文链接:https://blog.csdn.net/flyingcloud6/article/details/131352604

解释1、
1.1 如果每次需要的对象构造过程都比较复杂,那么就需要很多行的代码去能去创建一个对象。这样就比较麻烦!

1.2 如果在别的类中又需要创建该对象,那么代码的重复度就很高。

1.3 需要通过一个工具类,把每个对象创建的具体逻辑给隐藏起来,且只对外分别暴露一个调用方法。这样就减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。

1.4 该工具类就是工厂模式思想落地实现的一种具体情况,现在只不过很多框架都会自带工厂模式的实现接口。一般不需要我们自己手写,只需简单配置一下就可以使用了。

解释2、

主要是对对象的创建进行了一个封装;
因此也属于创建型模式。

目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

优点
一个调用者想创建一个对象,只要知道其名称就可以了;
扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以;
屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

三、简单工厂模式(Simple Factory)

结构组成:
工厂类(SimpleFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
抽象产品类(Car):是具体产品类的继承的父类或实现的接口。
具体产品类(BWM\Audi):工厂类所创建的对象就是此具体产品实例。

优点与不足:
优点: 结构简单,管理方式简单

缺点: 扩展性非常差,新增产品的时候,需要去修改工厂类。

举例子:具体产品类BMW、Audi,抽象产品类Car,工厂类SimpleFactory;

抽象产品类:用于存放一类特征相似的实现,并用于定义具体产品类。

工厂类:用于统计所有的特征,可以根据enum类型创建具体的产品对象。

class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};


好处:
可以看到,简单工厂可以做到,让用户创建对象的时候只需要知道对象的名称(BMW、AUDI)就好,而不需要关心创建对象的细节(BMW是如何建造的、型号是什么等等细节)。

不足:

每当我们想要扩展对象的时候(增加BENZ的对象)就需要在SimpleFactory类中添加代码,增加switch后面的case选项。这样一来,就需要修改源代码。灵活性非常的差!!!

那么,能不能做到添加对象的时候,不对现有代码进行修改呢?(也就是我们开发软件时候需要遵守的开-闭原则)

四、工厂模式

一个具体的工厂 生产一个具体的产品

结构组成:
抽象工厂类(Factory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(BMWFactory \AudiFactory ):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Car):它是具体产品继承的父类(基类)。
具体产品类(BWM\Audi):具体工厂所创建的对象,就是此类。

优点与不足
优点: 工厂方法模式抽象出了工厂类,并把具体产品对象的创建放到具体工厂类实现。实现了一个工厂生产一类产品,不需要修改工厂类,只需要增加新的具体工厂类即可。

缺点: 每新增一个产品,就需要增加一个对应的产品的具体工厂类。相比简单工厂模式而言,工厂方法模式需要更多的类定义。

抽象工厂类,提供了创建具体工厂类的纯虚函数,并通过具体工厂类来返回具体产品类;

抽象产品类同上;

举例子:

抽象工厂 + 具体工厂

//工厂方法:
class Factory
{
public:
	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);
	}
};
 
void main()
{
	Factory* bmwfty = new BMWFactory();
	Factory* audifty = new AudiFactory();
 
	Car* p1 = bmwfty->createCar("X6");
	Car* p2 = audifty->createCar("A6");
 
	p1->show();
	p2->show();
     
    // 释放资源
    delete adidasShoes;
    delete adidasProducer;
}

抽象产品 + 具体产品: 

class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};

当我们想要增加新的工厂:比如说奔驰工厂的时候,根本不用去管宝马和奥迪,只需要增加一个新的工厂就行了,所以说是符合了软件设计的          “开闭原则”   : 对已有的功能关闭,对扩展开放

好处:
可以做到不同的产品,在不同的工厂里面创建(模块化非常清晰),能够对现有工厂,以及产品的修改关闭

不足:
实际上,很多产品是有关联关系的,属于一个产品簇,不应该放到不同的工厂里面去创建,这样
一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护

五、抽象工厂模式

一个具体的工厂可生产多个产品。

工厂模式 已经能够满足基本的要求了,但是在实际生活中,比如宝马企业,不止有汽车,还有别的系列产品,比如:车灯、轮胎。。。也就是跟汽车有关的一组产品。这就需要“抽象工厂模式”。

重要区别:

工厂模式:只能生产一个产品。(要么BWM车、要么Audi车)

抽象工厂:可以一下生产一个产品族(里面有很多产品:BWM车\BWM车灯、Audi车\Audi车灯

结构组成(和工厂模式一样):
抽象工厂类厂(
AbstractFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(
BMWFactory\AudiFactory):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(
Car \Light):它是具体产品继承的父类(基类)。
具体产品类(
BMWCar\AudiCar、BmwLight\AudiLight):具体工厂所创建的对象,就是此类。

优点与不足:
优点: 提供一个接口,可以创建多个产品族中的产品对象,同一类的多个产品对象不需要创建多个工厂。

缺点: 相比简单工厂模式而言,抽象工厂模式需要更多的类定义。

举例子:

抽象产品类 + 具体产品类

//系列产品1:
class Car 
{
public:
	Car(string name):_name(name){}
	virtual void show()=0;
 
protected:
	std::string _name;
};
 
class BMW:public Car
{
public:
	BMW(string name):Car(name){}
	void show() {
		cout << "这是一辆宝马" << endl;
	}
};
 
class Audi :public Car
{
public:
	Audi(string name) :Car(name){}
	void show() {
		cout << "这是一辆奥迪" << endl;
	}
};
//系列产品 2:
class Light
{
public:
	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 Factory
{
public:
	virtual Car* createCar(string name) = 0;//工厂方法  创建汽车
	virtual Light* createLight() = 0;// 工厂方法  创建汽车关联的产品,车灯
};
//宝马工厂
class BMWFactory : public Factory
{
public:
	Car* createCar(string name) 
	{
		return new BMW(name);
	}
	Light* createLight()
	{
		return new BmwLight();
	}
};
//奥迪工厂
class AudiFactory : public Factory
{
public:
	Car* createCar(string name)
	{
		return new Audi(name);
	}
	Light* createLight()
	{
		return new AudiLight();
	}
};
void main()
{
	Factory* bmwfty = new BMWFactory();
	Factory* audifty = new AudiFactory();
 
	Car* p1 = bmwfty->createCar("X6");
	Car* p2 = audifty->createCar("A6");
	p1->show();
	p2->show();
 
	Light* l1 = bmwfty->createLight();
	Light* l2 = audifty->createLight();
	l1->show();
	l2->show();

    delete bmwfty; bmwfty = NULL;
    delete audifty; audifty= NULL;
    delete p1, p2; p1= NULL; p2= NULL;
    delete l1, l2; l1= NULL; l1= NULL;
}

六、应用场景

一、工厂模式应用到以下场景:

1、日志记录器

我们可以使用工厂方法模式来实现日志记录器,将客户端从具体的日志记录器实现中解耦出来,使得客户端只需要关注创建日志记录器的接口,而不用关心具体的实现方式。在这个场景中,我们可以定义一个抽象的Logger工厂接口,具体的文件日志记录器、数据库日志记录器等都实现这个接口并提供自己的创建方法,客户端可以通过调用Logger工厂接口的方法来创建相应的日志记录器。

2、图片读取器

在项目中,我们经常需要读取不同类型的图片,如bmp、jpeg、png等。使用工厂方法模式,我们可以定义一个抽象的ImageReader工厂接口,具体的BmpReader、JpegReader、PngReader等都实现这个接口并提供自己的创建方法,客户端可以通过调用ImageReader工厂接口的方法来创建相应类型的图片读取器。这样一来,我们可以在不同的图片读取器实现中,对图片的解析方式、压缩方式等进行优化和改进,而不需要修改客户端代码。

3、数据库访问器

在数据库操作中,我们经常需要使用到Connection、Statement、ResultSet等对象。使用工厂方法模式,我们可以定义一个抽象的DbConnector工厂接口,具体的MySqlConnection、OracleConnection、SqlServerConnection等都实现这个接口并提供自己的创建方法,客户端可以通过调用DbConnector工厂接口的方法来创建相应类型的数据库访问器。这样一来,我们可以在不同的数据库访问器实现中,对数据库连接、查询性能等进行优化和改进,而不需要修改客户端代码。

4、加密解密器

在项目中,我们经常需要对敏感数据进行加密和解密,如用户密码、信用卡号等。使用工厂方法模式,我们可以定义一个抽象的Encryptor工厂接口,具体的DesEncryptor、AesEncryptor、RsaEncryptor等都实现这个接口并提供自己的创建方法,客户端可以通过调用Encryptor工厂接口的方法来创建相应类型的加密解密器。这样一来,我们可以在不同的加密解密器实现中,对加密算法、安全性等进行优化和改进,而不需要修改客户端代码。

5、GUI控件

在图形界面程序中,我们经常需要使用各种GUI控件,如按钮、文本框、下拉框等。使用工厂方法模式,我们可以定义一个抽象的WidgetFactory工厂接口,具体的WinWidgetFactory、MacWidgetFactory、LinuxWidgetFactory等都实现这个接口并提供自己的创建方法,客户端可以通过调用WidgetFactory工厂接口的方法来创建相应类型的GUI控件。这样一来,我们可以在不同的GUI控件实现中,对界面风格、交互方式等进行优化和改进,而不需要修改客户端代码。

6、代码生成器

在一些代码生成器的开发中,我们需要根据不同的需求生成不同的代码,如Java代码、C++代码等。使用工厂方法模式,我们可以定义一个抽象的CodeGenerator工厂接口,具体的JavaCodeGenerator、CPlusPlusCodeGenerator等都实现这个接口并提供自己的创建方法,客户端可以通过调用CodeGenerator工厂接口的方法来创建相应类型的代码生成器。这样一来,我们可以在不同的代码生成器实现中,对代码风格、编译性能等进行优化和改进,而不需要修改客户端代码。

二、工厂模式 应用场景

(1)通常在使用word办公软件的时候,会根据需要绘制出饼状图,柱状图,折线图等图形。可以提供一个工厂类,根据用户的选择创建出不同类型的图形。

(2)QQ空间背景样式,博客背景样式等都提供了各种风格的样式。提供一个工厂,根据用户选择的具体风格样式,创建出各个不同的背景风格,用来装饰QQ空间。

(3)网页下载工具的开发: 根据需要可以下载新浪网页、腾讯网页、搜狐网页等。根据用户的选择,把网页类型传进工厂,将下载该类型的网页内容。

(4)淘宝购物最后一个支付环节,可以选择货到付款、网上银行、支付宝等类型支付。用户可以选择具体的支付方式完成订单,这也是简单工厂模式的一种应用。

(5)电影院打折算法: VIP5折、学生票5折、成人票正常收费等打折算法。

(6)多功能计算器的开发:封装加减乘除等运算操作(大话设计模式的例子)

(7)在很多游戏场合,游戏角色可以选择各种各样的武器,如:手枪、AK47、步枪、大刀等。

(8)如果电脑上装有QQ输入法、搜狗输入法、微软拼音输入法,用户可以设置使用哪种类型的输入法。类似的还可以设置IE浏览器、谷歌浏览器、火狐浏览器。可以设置word2003或者金山的WPS。这些都可以理解为简单工厂模式的一种运用。

(9)软件公司决策是否开发哪一种产品,银行卡识别、身份证识别还是驾驶证识别。

(10)生活中也有很多类似的工厂: 富士康代工工厂;安踏加工厂;咖啡生产基地;沃尔玛等超市提供各种产品供用户使用;肯德基马当劳等。

                 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

晶圆测量新利器:光谱共焦传感器优势解析

光谱共焦位移传感器和激光三角位移传感器在表面测量领域均占据重要位置&#xff0c;它们各自在测量物体厚度方面表现出独特的优势。尽管两者具备测量功能&#xff0c;但根据应用环境和所需精度&#xff0c;它们的适应性呈现出显著差异。 具体而言&#xff0c;光谱共焦位移传感器…

PSCA电源控制集成之分布式PPU

PPU的放置是一个重要考虑因素。最简单的方法是将所有的PPU都放置在SCP所在的始终开启的域中。将所有的PPU放置在一个层次结构中&#xff0c;集成问题&#xff0c;如地址映射、互连、时钟和复位等问题都比较简单。然而&#xff0c;有几个原因可能导致这不是最佳选择。 首先&…

Qt---项目代码解析

文章目录 一、main.cpp代码解析二、widget.h代码解析三、widget.cpp代码解析(一) form file 四、.pro Qt项目的工程文件 一、main.cpp代码解析 main函数的形参就是命令行参数。qt是CDefinitely图形界面化编程&#xff0c;要想编写一个qt的图形界面程序&#xff0c;一定要有QAp…

【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

蚂蚁感冒 刷题笔记

/* 解题思路 首先根据题意可知 1.蚂蚁速度均为1 即同向蚂蚁永远不可能追上 我们需要求最后感冒蚂蚁的数量 因为蚂蚁碰头将会掉头 效果和俩蚂蚁互相穿过继续走是一样的 所以我们将俩蚂蚁碰头视作穿过 2. 如果俩蚂蚁相向而行 则俩蚂蚁必定碰头 首先 我们获得第一个感冒蚂蚁的…

Vue+OpenLayers7入门到实战:OpenLayers7如何使用gifler库来实现gif动态图图片叠加到地图上

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 OpenLayers7本身不支持gif图片作为图标要素显示到地图上,所以需要通过其他办法来实现支持gif图片。 本章介绍如何使用OpenLayers7在地图上使用gifler库先生成canvas画板,然后通过canvas画板的重绘事件来重新渲染地图…

URL输入到页面渲染过程详解

当我们在浏览器中输入一个URL并按下回车键时&#xff0c;浏览器会执行一系列步骤来解析URL、发送请求、接收响应&#xff0c;并最终渲染页面。这个过程涉及到多个阶段&#xff0c;包括DNS解析、TCP握手、发送HTTP请求、服务器处理请求、返回HTTP响应、浏览器解析和渲染等。下面…

19-Java中介者模式 ( Mediator Pattern )

Java中介者模式 摘要实现范例 中介者模式&#xff08;Mediator Pattern&#xff09;提供了一个中介类&#xff0c;该类通常处理不同类之间的通信&#xff0c;并支持松耦合&#xff0c;使代码易于维护中介者模式是用来降低多个对象和类之间的通信复杂性中介者模式属于行为型模式…

算法刷题Day2 | 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II

目录 0 引言1 有序数组列表1.1 我的题解&#xff08;双指针&#xff09;1.2 根据官方解题修改后 2 长度最小的子数组2.1 我的题解2.2 官方滑动窗口&#xff08;双指针&#xff09;题解 3 螺旋矩阵3.1 我的题解 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&…

CXYGZL实现钉钉、飞书和微信全面覆盖!!!

非常欣慰能在这里与大家分享&#xff0c;CXYGZL已圆满实现多端互通的目标&#xff01;&#xff01;&#xff01; 无论您是在手机、电脑还是平板上使用钉钉、企微还是飞书&#xff0c;只需将CXYGZL轻松集成到您的办公软件中&#xff0c;即可实现无缝审批处理各项任务&#xff0c…

FreeRTOS_day2

作业&#xff1a;1.使用ADC采样光敏电阻数值&#xff0c;如何根据这个数值调节LED灯亮度。 2.总结DMA空闲中断接收数据的使用方法 打开DAM,允许接收外部设备数据&#xff0c;调用中断接收回调函数

王道机试C++第 3 章 排序与查找:排序问题 Day28(含二分查找)

查找 查找是另一类必须掌握的基础算法&#xff0c;它不仅会在机试中直接考查&#xff0c;而且是其他某些算法的基础。之所以将查找和排序放在一起讲&#xff0c;是因为二者有较强的联系。排序的重要意义之一便是帮助人们更加方便地进行查找。如果不对数据进行排序&#xff0c;…

热插拔更换ESXI宿主机系统硬盘导致紫屏故障案例一则

关键词 vmware、esxi5.5raid、热插拔、紫屏 华为 CH121V3刀片、SSD硬盘 There are many things that can not be broken&#xff01; 如果觉得本文对你有帮助&#xff0c;欢迎点赞、收藏、评论&#xff01; 一、问题现象 现网vmware云平台一台华为E9000刀箱CH121V3刀片服务…

面试经典150题——环形链表

Suffering, for the weak is the tomb of death, and for the strong is the soil of germinal ambition.​ 1. 题目描述 2. 题目分析与解析 2.1 思路一 这个题目就是判断一个链表有没有环&#xff0c;其实我们之讲过一个题目&#xff0c;就实现了判断链表有没有环的步骤&a…

1 数据分析概述与职业操守 (3%)

1、 EDIT数字化模型 E——exploration探索 &#xff08;是什么&#xff09; 业务运行探索&#xff1a;探索关注企业各项业务的运行状态、各项指标是否合规以及各项业务的具体数据情况等。 D——diagnosis 诊断 (为什么) 问题根源诊断&#xff1a;当业务指标偏离正常值时&…

C#,哈夫曼编码(Huffman Code)压缩(Compress )与解压缩(Decompress)算法与源代码

David A. Huffman 1 哈夫曼编码简史&#xff08;Huffman code&#xff09; 1951年&#xff0c;哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是&#xff0c;寻找最有效的二进制编码。由于无法证明哪个已有编码是…

GCN 翻译 - 2

2 FAST APROXIMATE CONVOLUTIONS ON GRAPHS 在这一章节&#xff0c;我们为这种特殊的的图基础的神经网络模型f(X, A)提供理论上的支持。我们考虑一个多层的图卷积网络&#xff08;GCN&#xff09;&#xff0c;它通过以下方式进行层间的传播&#xff1a; 这里&#xff0c;是无…

Spring事务注解@Transactional的流程和源码分析

Spring事务简介 Spring事务有两种方式&#xff1a; 编程式事务&#xff1a;编程式事务通常使用编程式事务管理API实现&#xff0c;比如Spring提供的PlatformTransactionManager接口&#xff0c;使用它操控事务。声明式事务&#xff1a;注解式事务使用AOP&#xff08;面向切面…

【24春招/简历】如果技术和学历不行,如何包装自己在春招中占得先机?突出你的亮点!

面试讲什么 学历&#xff1a; 行情 要美化&#xff08;吹牛&#xff09; 面试很好 技术能力 让面试官知道你会哪些技术&#xff0c;尽量细节 “熟悉spring” > ioc流程&#xff0c;Bean的生命周期&#xff0c;循环依赖&#xff0c;常见注解 熟悉redis > 缓存穿透&…

【Java设计模式】八、装饰者模式

文章目录 0、背景1、装饰者模式2、案例3、使用场景4、源码中的实际应用 0、背景 有个快餐店&#xff0c;里面的快餐有炒饭FriedRice 和 炒面FriedNoodles&#xff0c;且加配菜后总价不一样&#xff0c;计算麻烦。如果单独使用继承&#xff0c;那就是&#xff1a; 类爆炸不说&a…
最新文章