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

简单工厂模式 创建型模式(非GoF经典设计模式)

        简单工厂模式是属于创建型模式,也因为工厂中的方法一般设置为静态,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

1.示例代码解读

//简单工厂模式工厂代码
#include <iostream>
using namespace std;//抽象产品
class AbstractProduct
{
public:virtual ~AbstractProduct() {}virtual void Operation() = 0;
};class SimpleFactory
{
public:static AbstractProduct* CreateProduct(const std::string& type);
};int main()
{AbstractProduct* productA = SimpleFactory::CreateProduct("A");productA->Operation();AbstractProduct* productB = SimpleFactory::CreateProduct("B");productB->Operation();delete productA;delete productB;return 0;
}

1.1 核心函数

        设计模式只是我们总结的一种方法论,我想强调的是,设计模式仅仅是我们做事情的方法或者说是套路,而我们应用它的目的是为了解决我们的问题本身。先不要觉得的思路有点儿莫名其妙,我先请大家回答一个问题,在上述的代码里,真正的核心是哪一个函数?或者说与业务最相关的是哪个函数?  没错,是Operation(),就是这个函数。 

        我们搞了那么多套路,那么多设计模式,无非就是为了调用Operation()函数,完成我们想要完成的工作不是么?比如Opertion()函数是用来读某一种格式的文件的。但是我再问大家一个问题,你在使用这个函数的时候,你需要关心它具体是怎么做的么?比如它读一个txt,你会关心它具体怎么去解析这个问题的内容么?往往不会对么,除非你是负责做文件解析的,但是在使用这段代码的时候,当时的角色一定不是为了做文件解析本身,而是想要拿到文件解析的成果。而事实上,大多数情况下,你根本是拿不到Operation()实现的具体代码细节。就比如上述的代码,你只看到了这个函数接口,而拿不到函数实现。

1.2 迪米特法则

        大家发现没有,我们最关心的Operation(),我们既不知道它具体是怎么实现的(但是我们当然得知道它用来做什么,这个一般会写上接口说明,如果你连这个函数的作用都不知道,你还用个der)。事实上,我们连具体是什么类型的对象的函数也不知道(我们只知道它的抽象类)。看到没,这样一种封装是不是做的很漂亮很极致,不该知道的你都不知道,都被完美的封装起来了。这就是迪米特法则,又称最少知道原则(Demeter Principle)。也就是说,你只需要知道你需要选择创建什么样的类型的“产品”,来执行你的操作就好了。还是用解析文件的例子,比如你需要解析的文件是txt格式的,那你就选择解析txt格式的“产品”,如果你需要解析“jpg”格式的产品你就设置对应的类型即可。创建完对应的类型,直接调用Operation()函数,即可完成工作,是不是非常的无脑简单。

1.3 扩展问题

        这个时候聪明的同学就会问了,如果我想解析一种新的文件格式咋整。好,那就要涉及到需要增加新“产品”的问题了。这个时候你就需要请做这个工厂模式文件解析库的同学来帮忙了。我们来看看他在扩展这个需求的时候需要做什么工作。这里我们需要把全部的核心的简单工厂模式代码打开来看。

//简单工厂模式工厂代码
#include <iostream>
using namespace std;//抽象产品
class AbstractProduct
{
public:virtual ~AbstractProduct() {}virtual void Operation() = 0;
};class SimpleFactory
{
public:static AbstractProduct* CreateProduct(const std::string& type);
};int main()
{AbstractProduct* productA = SimpleFactory::CreateProduct("A");productA->Operation();AbstractProduct* productB = SimpleFactory::CreateProduct("B");productB->Operation();delete productA;delete productB;return 0;
}//具体产品
class ProductA : public AbstractProduct
{
public:void Operation() {cout << "ProductA" << endl;}
};//具体产品B
class ProductB : public AbstractProduct {
public:void Operation() {cout << "ProductB" << endl;}
};AbstractProduct* SimpleFactory::CreateProduct(const std::string& type){if (type == "A")return new ProductA();else if (type == "B")return new ProductB();elsereturn nullptr;}

这里我偷了个懒,没有把声明和实现分开放在.h和.cpp文件里,大家知道就行。大家可以看到,main函数之下的代码就是具体的实现代码了。我们在第一份代码里,看到有A,B两个产品。现在我们需要增加C产品。我们要改两个地方:

  1. 需要再派生一个具体的产品类C,且实现Opertion()函数的具体功能。
  2. 工厂的CreateProduc函数需要做新增的判断。

最后我们的这个简单工厂模块需要重新编译(一般都是以链接库的方式提供给其他人调用)。到此位置我们代码解读部分就完成了。

2.组成结构

简单工厂模式包含以下几个主要组成部分:

  1. Factory(简单工厂):核心部分,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象。
  2. Product(抽象类产品):工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象。
  3. ConcreteProduct(具体产品):简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实例。它要实现抽象产品中声明的抽象方法(有关抽象类)。

3.工作流程

简单工厂模式的工作流程如下:

  1. 客户端通过调用工厂类的方法来请求一个产品对象。
  2. 工厂类根据客户端的请求,决定实例化哪个具体产品对象。
  3. 工厂类实例化具体产品对象,并将其返回给客户端。
  4. 客户端通过产品接口操作具体产品对象。

3.优缺点

2.1 优点

  1. 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
  2. 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
  3. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

总结:只需要传入一个正确的参数,就可以获取你所需要的对象而无需知道其创建对象的细节

2.2 缺点

  1. 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
  2. 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  3. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  4. 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

总结:扩展性差,当增加新的产品需要修改工厂类的判断逻辑,违背开闭原则,如我想要买一个华为手机的话,除了新增华为手机这个产品类,还需要修改工厂中的逻辑

4.应用场景

  1. 创建型模式:简单工厂模式是一种创建型模式,它的主要目的是为了实现解耦,将对象的创建和使用分开,即应用程序将对象的创建和初始化职责交给工厂对象。通过简单工厂,实现了调用类和具体实现类的解耦,使用者不需要知道具体的创建过程,只需要使用即可。
  2. 封装具体实现:如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装类,那么可以选择简单工厂模式。通过简单工厂,可以将对外创建对象的职责集中管理和控制。
  3. 降低代码重复:如果对象B的创建过程比较复杂,并且很多地方都用到了,那么很可能出现很多重复的代码。通过统一将创建对象B的代码放到工厂里面统一管理,可以减少代码的重复率,同时也方便维护。
  4. 处理子类:当类本身有很多子类,并且经常性发生变化时,可以使用简单工厂模式。

5.引用

设计模式简单学——简单工厂模式 (baidu.com)

相关文章:

简单工厂模式 创建型模式(非GoF经典设计模式)

简单工厂模式是属于创建型模式&#xff0c;也因为工厂中的方法一般设置为静态&#xff0c;又叫做静态工厂方法&#xff08;Static Factory Method&#xff09;模式&#xff0c;但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工…...

PE文件之导入表

1. 导入表 2. 显示导入表信息的例子 ; 作用: 将RVA地址转成FOA即文件偏移 ; 参数: _pFileHdr 指向读到内存中文件的基址指针 ; _dwRVA 目标RVA地址 ; 返回: 目标RVA转成文件偏移的值 RVA2FOA PROC USES esi edi edx, _pFileHdr:PTR BYTE, _dwRVA:DWORDmov esi, _pFil…...

二、码制及其转换

原码 根据我们所学可知&#xff0c;数字电路的逻辑电路是通过输出0和1来表示二进制数的&#xff0c;那么这个二进制数的正负又该怎么表示呢&#xff1f; 答案是在这个二进制数的最高位作为符号位来表示正负性&#xff0c;用0正数&#xff0c;用1表示负数&#xff0c;在这种表达…...

在pycharm中出现下载软件包失败的解决方法

一. 一般情况下我们会选择在设置中下载软件包,过程如下. 1. 直接点击左上角的文件, 再点击设置, 再点击项目, 在右边选择python解释器,点击号,输入要下载的软件包, 在下面的一系列的包中选择相对应的包,点击安装就可以了,有的时候我们下载的是最新的版本,如果要下载固定的版本…...

10.0 探索API调试事件原理

本章笔者将通过Windows平台下自带的调试API接口实现对特定进程的动态转存功能&#xff0c;首先简单介绍一下关于调试事件的相关信息&#xff0c;调试事件的建立需要依赖于DEBUG_EVENT这个特有的数据结构&#xff0c;该结构用于向调试器报告调试事件。当一个程序发生异常事件或者…...

文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题

二、用go语言&#xff0c;说明如何在一个数组 A[1…n]中实现两个栈&#xff0c;使得当两个栈的元素个数之和不为 n 时&#xff0c;两者都不会发生上溢。要求 PUSH 和 POP 操作的运行时间为 O(1)。 文心一言&#xff1a; 在这个问题中&#xff0c;我们要在一个数组 A[1…n] 中…...

检测防火墙是否开启、判断程序是否加入防火墙白名单(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…...

vtk 动画入门 1 代码

实现效果如图&#xff1a; #include <vtkAutoInit.h> //VTK_MODULE_INIT(vtkRenderingOpenGL2); //VTK_MODULE_INIT(vtkInteractionStyle); VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); //VTK_MODULE_INIT(vtkRenderingFreeType); #in…...

【VR】【unity】如何在VR中实现远程投屏功能?

【背景】 目前主流的VD应用,用于娱乐很棒,但是用于工作还是无法效率地操作键鼠。用虚拟键盘工作则显然是不现实的。为了让自己的头显能够起到小面积代替多显示屏的作用,自己动手开发投屏VR应用。 【思路】 先实现C#的投屏应用。研究如何将C#投屏应用用Unity 3D项目转写。…...

OpenGl材质

在现实世界里,每个物体会对光产生不同的反应。比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光。有些物体反射光的时候不会有太多的散射(Scatter),因而产生较小的高光点,而有些物体则会散射很多,产生一个有着更大半径的…...

背包问题

目录 开端 01背包问题 AcWing 01背包问题 Luogu P2925干草出售 Luogu P1048采药 完全背包问题 AcWing 完全背包问题 Luogu P1853投资的最大效益 多重背包问题 AcWing 多重背包问题 I AcWing 多重背包问题 II Luogu P1776宝物筛选 混合背包问题 AcWing 混合背包问题…...

JavaSE | 初始Java(十一) | 抽象类和抽象接口

抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c; 如果 一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类 在 Java 中&#xff0c;一个…...

产品经理如何科学的进行需求调研?

导语&#xff1a;作为产品经理&#xff0c;需求调研是开展工作的重要环节之一。科学、有效地进行需求调研不仅可以帮助产品经理更好地了解用户需求&#xff0c;还能指导产品设计和功能开发&#xff0c;提升产品的竞争力。本文将介绍几种科学的方法和技巧&#xff0c;帮助产品经…...

AI智能问答系统源码/AI绘画商业系统/支持GPT联网提问/支持Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的AI智能问答系统和AI绘画系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图…...

玩具玩偶配送经营商城小程序的作用是什么?

玩具玩偶是小孩子们喜欢的产品&#xff0c;其市场需求度很高&#xff0c;以前玩具店里总是不缺乏客户&#xff0c;但现在随着人们生活品牌提升及消费形式改变&#xff0c;无论玩具厂商还是门店经销商都面对着不少痛点&#xff1a; 如拓客引流难、线上销售经营难、营销难、分销…...

latex表格内容换行

问题描述&#xff1a; 在用latex表格中编写公式时&#xff0c;可能出现公式太长&#xff0c;表格中后面的内容不能在文档中呈现&#xff0c;如下图1&#xff0c;故要进行行内内容的换行&#xff0c;使内容呈现完全而传统的\换行后,换行内容会顶格&#xff0c;如图2。 解决方…...

2023 牛客国庆day4 【10.2训练补题】

目录 B-Basic Gcd Problem&#xff08;素数筛快速幂&#xff09; H-Harder Gcd Problem&#xff08;素数&#xff09; B-Basic Gcd Problem&#xff08;素数筛快速幂&#xff09; 打表找规律发现答案为 (n质因子数目)^c #include<bits/stdc.h> using namespace std;…...

android的USB开发时 mUsbManager.getDeviceList()获取都为空

类提供的主要方法有&#xff1a; getDeviceList() 获得设备列表&#xff0c;返回的是一个HashMap.;hasPermission(UsbDevice device) 判断你的应用程序是否有接入此USB设备的权限&#xff0c;如果有则返回真&#xff0c;否则返回false.openDevice(UsbDevice device) 打开USB设…...

SpringCloud Alibaba - Seata 部署 TC 服务,并集成微服务

目录 一、Seata 架构 1.1、Seata 架构重要角色 1.2、部署 TC 服务 1.2.1、前言 1.2.2、下载 seata-server 包&#xff0c;解压 1.2.3、修改配置 1.2.4、在 nacos 中添加配置 1.2.5、创建数据库表 1.2.6、启动 TC 服务 1.3、微服务集成 Seata 1.3.1、引入依赖 1.3.2、…...

Java基础面试,接口和抽象类的区别?

接口和抽象类的区别&#xff1f; 抽象类可以存在普通成员函数&#xff0c;而接口中只能存在public abstract 方法。抽象类中的成员变量可以是各种类型的&#xff0c;而接口中的成员变量只能是public static final类型的.抽象类只能继承一个&#xff0c;接口可以实现多个。 接…...

《视觉 SLAM 十四讲》V2 第 4 讲 李群与李代数 【什么样的相机位姿 最符合 当前观测数据】

P71 文章目录 4.1 李群与李代数基础4.1.3 李代数的定义4.1.4 李代数 so(3)4.1.5 李代数 se(3) 4.2 指数与对数映射4.2.1 SO(3)上的指数映射罗德里格斯公式推导 4.2.2 SE(3) 上的指数映射SO(3),SE(3),so(3),se(3)的对应关系 4.3 李代数求导与扰动模型4.3.2 SO(3)上的李代数求导…...

【深蓝学院】手写VIO第4章--基于滑动窗口算法的 VIO 系统:可观性和 一致性--笔记

0. 内容 T1. 参考SLAM14讲P247直接可写&#xff0c;注意 ξ 1 , ξ 2 \xi_1,\xi_2 ξ1​,ξ2​之间有约束&#xff08;关系&#xff09;。 套用舒尔补公式&#xff1a; marg掉 ξ 1 \xi_1 ξ1​之后&#xff0c;信息被传递到 L 1 和 L 2 L_1和L_2 L1​和L2​之间了。 T2....

mfc 动态加载dll库,Mat转CImage,读ini配置文件,鼠标操作,在edit控件上画框,调试信息打印

动态加载dll库 h文件中添加 #include "mydll.h" #ifdef UNICODE //区分字符集 #define LoadLibrary LoadLibraryW #else #define LoadLibrary LoadLibraryA #endif // !UNICODEtypedef double(*mydllPtr)(int, int);类内添加&#xff1a; mydllPtr m_mydll; cpp…...

索尼 toio™应用创意开发征文|检测工业平台震动

虽然索尼toio Q宝机器人主要是为儿童教育娱乐开发的&#xff0c;但我认为它在工业等领域也有一定应用潜力。例如&#xff0c;工业领域经常会有某些平面在实际作业中持续震动&#xff0c;导致零件过疲劳、平台失去稳定等问题。而这样的平台往往位于机器内部&#xff0c;从外部很…...

【已解决】 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘.

问题描述 团队都是用mac&#xff0c;只有我自己是windows&#xff0c;启动项目一直报错 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘. 但我不能因为自己的问题去改团队配置&#xff0c;也尝试过该vscode配置默认是LF还是报错 思路 看文章vscode如何替换所有文件的…...

Java8 Lambda.stream.sorted() 方法使用浅析分享

文章目录 Java8 Lambda.stream.sorted() 方法使用浅析分享sorted() 重载方法一升序降序 sorted() 重载方法二升序降序多字段排序 mock代码 Java8 Lambda.stream.sorted() 方法使用浅析分享 本文主要分享运用 Java8 中的 Lambda.stream.sorted方法排序的使用&#xff01; sorted…...

Neural Networks for Fingerprint Recognition

Neural Computation ( IF 3.278 ) 摘要&#xff1a; 在采集指纹图像数据库后&#xff0c;设计了一种用于指纹识别的神经网络算法。当给出一对指纹图像时&#xff0c;算法输出两个图像来自同一手指的概率估计值。在一个实验中&#xff0c;神经网络使用几百对图像进行训练&…...

ChatGPT推出全新功能,引发人工智能合成声音担忧|百能云芯

人工智能AI科技企业OpenAI公司25日宣布&#xff0c;其聊天应用程序ChatGPT如今具备「看、听、说」能力&#xff0c;至少能够理解口语、用合成语音回应并且处理图像&#xff1b;但专家忧心&#xff0c;以假乱真与深度伪造的乱象可能变本加厉。 国家广播公司新闻网(NBC News)报导…...

Java 实现遍历一个文件夹,文件夹有100万数据,获取到修改时间在2天之内的数据

目录 1 需求2 实现1&#xff08;第一种方法&#xff09;2 实现2 &#xff08;推荐使用这个&#xff0c;快&#xff09;3 实现3&#xff08;推荐&#xff09; 1 需求 现在有一个文件夹&#xff0c;里面会一直存数据&#xff0c;动态的存数据&#xff0c;之后可能会达到100万&am…...

持续集成部署-k8s-命令行工具:基础命令的使用

持续集成部署-k8s-命令行工具:基础命令的使用 1. 资源类型与别名2. 资源操作2.1 创建对象2.2 显示和查找资源2.3 更新资源2.4 修补资源2.5 编辑资源2.6 scale 资源2.7 删除资源3. 格式化输出1. 资源类型与别名 资源类型缩写别名clusterscomponentstatusescsconfigmapscmdaemon…...

政府网站信息内容建设/推广普通话手抄报模板可打印

在程序执行过程中&#xff0c;操作系统会进行线程调度&#xff0c;同一时刻能同时执行的程序数量跟CPU的内核线程数有关&#xff0c;比如4核CPU&#xff0c;同时最多只能有4个线程。Go 语言中的运行时系统也会对goroutine进行调度&#xff0c;调度器会频繁地让goroutine处于中断…...

深圳免费做网站/网络运营seo是什么

7 月 12 日&#xff0c;Python 之父 Guido van Rossum 在 Python 邮件组里发邮称&#xff0c;他将退出 Python 核心决策层&#xff0c;而转居幕后。从 Guido van Rossum 的邮件内容可以看出&#xff0c;他已经厌倦了运营该组织。他在邮件开头写道&#xff0c;「我不想再为 PEP&…...

wordpress 更改标题/平台推广公众平台营销

文章目录一、栈实现计数器思路1、两个栈来保存字符2、比较优先级和计算3、过程会使用到的函数3.1、boolean recognize(char ch)区别是数字还是操作符3.2、int priority(char ch)&#xff0c;用来比较优先级3.3、int operateNum(int num1, int num2, char ch)二、用代码实现三、…...

python 视频播放网站开发/衡水seo培训

近日&#xff0c;在某微博上看到有人推荐了这本作者是 雨痕 的《Python学习笔记》&#xff0c;从github上下载下来看了下&#xff0c;确实很不错。 注意&#xff0c;这本学习笔记不适合Python新手学习。 从目录上看&#xff0c;并不能看出这本笔记有何特别之处&#xff0c;但…...

浙江广厦建设职业技术学院招生网站/长尾关键词爱站网

1、确认系统已经安装了SSH。rpm –qa | grep opensshyum install ssh -y ##安装SSH协议2、生成秘钥对ssh-keygen -t rsa -P ##直接回车生成的密钥对&#xff1a;id_rsa和id_rsa.pub&#xff0c;默认存储在用户的目录下 如&#xff1a;/home/oldboy/.ssh。 如下&#xff1…...

济南网站建设公司晟创未来/软文世界平台

1、高考的失利&#xff0c;只是一时的成败。 2、被生活逼出的动力&#xff0c;你真的有曾感到绝望吗&#xff1f; 3、找到方向很重要&#xff0c;你可能与我一样&#xff0c;只是差了一位引路人。 4、兴趣是最好的老师&#xff0c;持续编程是我唯一坚持超过一年的事情 5、短…...