C# 创建型设计模式----工厂模式
1 、什么是工厂模式
简单来说就是由一个对象去生成不同的对象,工厂模式是用工厂方法代替new操作的一种模式。工厂方法封装了多个相关联类的new方法,每次实例化这些类的时候不需要new多次,只需要调用工厂类的对应方法即可实例化这些类,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式主要有三种类型:简单工厂(不介绍)、工厂方法和抽象工厂。
2、工厂模式的作用
在创建对象时必然需要new该对象,当需要更改对象时,需要把项目中所有地方都修改一遍,这显然违背了软件设计的开闭原则。如果使用工厂来生成对象,那么我们只需要跟工厂打交道就可以了。如果要更新对象时,直接在工厂里更换即可。这就实现了对象解耦。
所以工厂模式主要用来解耦代码,将对象的创建和使用分离,使得代码更加灵活和可维护。
3、工厂方法
3.1、工厂方法模式的主要角色:
抽象工厂:在抽象工厂类中声明了工厂方法,用于返回一个产品。提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
具体工厂:它是抽象工厂类的子类,实现了在抽象工厂中声明的工厂方法,完成具体产品的创建。并可由客户端调用,返回一个具体产品类的实例。
抽象产品:它是定义产品的接口,定义了产品的规范,描述了产品的主要特性和功能,是工厂方法模式所创建对象的公共父类。
具体产品:它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间相互对应。
3.2、创建工厂方法
抽象工厂:提供基类,通俗理解就是。有这么一个专门生产电蒸锅的集团架构(别问为什么是电蒸锅,因为我现在想买)。集团不提供锅,只提供流水线的基建,和产品的基本概念。
/// <summary>///抽象工厂--电蒸锅集团,专门生产各种电蒸锅/// </summary>public abstract class ElectricFactory{/// <summary>/// 声明获取抽象产品类方法(具体实现在其子类)--提供生产电蒸锅的流水线,流水线具体怎么生产,生产哪种集团不管/// </summary>/// <returns></returns>public abstract Electric GetElectric();}
具体工厂:继承抽象工厂--也就是具体的生产厂家,都是继承集团的流水线并定义里面具体的生产方式
/// <summary>
/// 具体工厂-美的流水线
/// </summary>
public class MDElectricFactory : ElectricFactory//美的属于该集团下的工厂
{/// <summary>/// 实现抽象方法,具体操作在里面/// </summary>/// <returns></returns>public override Electric GetElectric()//美的使用集团提供的流水线,集团提供什么,美的就能使用什么{Console.WriteLine("美的生产了一个锅");return new MDElectric();//返回具体产品-美的电蒸锅}
}
/// <summary>
/// 具体工厂-苏泊尔流水线
/// </summary>
public class SBRElectricFactory : ElectricFactory//苏泊尔属于该集团下的工厂
{/// <summary>/// 实现抽象方法,具体操作在里面/// </summary>/// <returns></returns>public override Electric GetElectric()//使用集团提供的流水线{Console.WriteLine("苏泊尔生产了一个锅");return new SBRElectric();//返回具体产品-苏泊尔电蒸锅}
}
抽象产品:集团告诉你这是电蒸锅,它有什么功能,下面的工厂生产的产品得有这个功能,至于功能怎么实现的集团不管。
/// <summary>
/// 抽象产品电蒸锅---集团定义的电蒸锅整个品类
/// </summary>
public abstract class Electric
{/// <summary>/// 抽象方法-定义电蒸锅有蒸东西的基本功能,具体怎么蒸就是下面的厂家决定。/// </summary>public abstract void Fun();/// <summary>/// 抽象产品提供拓展方法--子类产品非必须使用的,但可以有,就像有些电蒸锅有预约功能,有些没有。/// 而且最好是具体产品的共有的特性(公共方法),不建议是小众特性(仅适用于某个具体产品的方法),/// 例如电蒸锅的预约功能就很大众,可以有,/// 如果某个厂家要加一个烤盘功能,这就属于小众,放在具体厂家那里去实现更合适。/// </summary>public void AddFunction(string name){Console.WriteLine($"{name}加了一个预约功能");}
}
具体产品:电蒸锅的蒸东西的功能具体实现方式
/// <summary>/// 具体产品-美的电蒸锅/// </summary>public class MDElectric : Electric//这是美的电蒸锅,必须包含集团定义的电蒸锅的必备功能的同时也可以自己拓展{/// <summary>/// 具体的实现方法/// </summary>public override void Fun(){Console.WriteLine("美的电蒸锅蒸东西的功能是用大火蒸东西");}}/// <summary>/// 具体产品-苏泊尔电蒸锅/// </summary>public class SBRElectric : Electric//这是苏泊尔电蒸锅{public override void Fun(){Console.WriteLine("苏泊尔电蒸锅蒸东西的功能是用中火蒸东西");}}
使用:
private void WTBtn_Click(object sender, EventArgs e)
{ElectricFactory electric;//创建了一个电蒸锅集团。electric = new MDElectricFactory();//美的接入集团var DZG = electric.GetElectric();//美的使用集团生产线,定义生产线的具体流程并生产一个锅DZG.Fun();//这个锅实现具体的功能electric = new SBRElectricFactory();//苏泊尔接入集团var DZG1 = electric.GetElectric();//苏泊尔使用集团生产线,定义生产线的具体流程并生产一个锅DZG1.Fun();//这个锅实现具体的功能DZG1.AddFunction("苏泊尔");//看到电蒸锅大类(抽象产品)里可以加一个功能,让苏泊尔给这个锅加一个。
}
运行结果:
通过调用方式可以看出,不同产品的生产由原来的总工厂变为了各个分工厂去负责。
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。
这就是一整个工厂方法。当然这样看下来估计也是懵懂的不知道它有什么作用。
我再用文字尝试说明一下:
来设想你现在需要开发一个电商平台的订单模块,其中需要生成不同类型的订单,比如普通订单、促销订单、团购订单等。每个订单里面有很多的参数。
按照常规的方式,我们直接创建每个订单类,然后全部new出来即可, 这样就没必要创建什么工厂类了对吧?
假设订单类名是OrderA、OrderB、OrderC。有很多参数的情况下New就得
OrderA A=new OrderA(参数1,参数2,.....);
要使用里面具体方法还得
A.方法1();A.方法2();........
但是现在你有各种各样的订单,这些订单是你不同的同事去开发的。如果按你上面的做法,首先你需要知道每一个订单类的情况,你需要知道要成功new出一个具体的订单类需要哪些参数、需要执行哪些方法。但是这明显是不现实的,你没有时间去看源码,甚至看不到源码。
因为你的工作只是new出订单类并调用里面的方法罢了,而每个订单类具体怎么写,其实你不需要知道,这个时候每个订单类对应一个具体的工厂类,你只需要调用工厂里的创建产品方法就行了。
再者从单依职责原则,解耦合来考虑。如果按常规new OrderA的写法,你的同事某个订单类修改了,势必会导致你写的程序会直接创建报错,你就得跟着修改。但是使用了工厂方法,根本不会影响你,因为你不参与创建实例,你的程序也不需要任何的改动。你的同事如何修改订单类跟你也没关系。
嗯.....这样说不知道有没有说明白它的作用。。。
4、抽象工厂
上面工厂模式不管工厂怎么拆分抽象,都只是针对一类产品,直接生成实例,这些工厂只生产同种类产品。
但是抽象工厂模式不同,抽象工厂模式并不直接生成实例, 而是用于对产品类簇的创建。
通俗点来讲就是:简单工厂和工厂方法模式的工作是生产产品,那么抽象工厂模式的工作就是生产工厂的。
是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
抽象工厂的最大好处在于交换产品系列非常方便,只需要改变具体工厂即可使用不同的产品配置。
总的来说工厂方法模式一个工厂只生产一个产品,抽象工厂模式一个工厂生产多个产品,形成一个产品套餐,而多个工厂组成套餐系列。
4.1、抽象工厂模式的主要角色:
抽象工厂:在抽象工厂类中声明了多个工厂方法,用于返回多个产品。提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
具体产品工厂:它是抽象工厂类的子类,实现了在抽象工厂中声明的多个工厂方法,完成多个具体产品的创建。
抽象产品:它是定义一个产品的接口,定义了一个产品的规范,描述了一个产品的主要特性和功能。抽象工厂模式有多个抽象产品。
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
4.2 创建方式
抽象工厂:有多少个系列就可以创建多少个抽象工厂类。本实例只创建了一个电器系列的工厂。里面可以有许多同系列的电器产品。
/// <summary>
///抽象工厂--电器集团,专门生产各种电器
/// </summary>
public abstract class ElectricFactory
{/// <summary>/// 生产电蒸锅/// </summary>/// <returns></returns>public abstract Electric GetElectric();/// <summary>/// 生产电饭煲/// </summary>/// <returns></returns>public abstract Rice GetRice();
}
具体工厂:同一系列可以创建多个具体的工厂,负责同一系列下的不同产品出的创建。本示例是电器下的电蒸锅和电饭煲,当然还可以电视机,烧水壶啥的。
/// <summary>/// 具体工厂-美的工厂/// </summary>public class MDFactory : ElectricFactory//美的属于该集团下的工厂{public override Electric GetElectric(){Console.WriteLine("美的生产了一个电蒸锅");return new MDElectric();//返回具体产品-美的电蒸锅}public override Rice GetRice(){Console.WriteLine("美的生产了一个电饭煲");return new MDRice();}}/// <summary>/// 具体工厂-苏泊尔工厂/// </summary>public class SBRFactory : ElectricFactory//苏泊尔属于该集团下的工厂{/// <summary>/// 实现抽象方法,具体操作在里面/// </summary>/// <returns></returns>public override Electric GetElectric()//使用集团提供的流水线{Console.WriteLine("苏泊尔生产了一个电蒸锅");return new SBRElectric();//返回具体产品-苏泊尔电蒸锅}public override Rice GetRice(){Console.WriteLine("苏泊尔生产了一个电饭煲");return new SBRRice();}}
抽象产品:有多少个不同产品就创建多少个抽象产品类。
/// <summary>/// 抽象产品电蒸锅---集团定义的电蒸锅整个品类/// </summary>public abstract class Electric{/// <summary>/// 抽象方法-定义电蒸锅有蒸东西的基本功能,具体怎么蒸就是下面的厂家决定。/// </summary>public abstract void Fun();/// <summary>/// 抽象产品提供拓展方法--子类产品非必须使用的,但可以有,就像有些电蒸锅有预约功能,有些没有。/// 而且最好是具体产品的共有的特性(公共方法),不建议是小众特性(仅适用于某个具体产品的方法),/// 例如电蒸锅的预约功能就很大众,可以有,/// 如果某个厂家要加一个烤盘功能,这就属于小众,放在具体厂家那里去实现更合适。/// </summary>public void AddFunction(string name){Console.WriteLine($"{name}加了一个预约功能");}}/// <summary>/// 抽象产品-电饭煲/// </summary>public abstract class Rice{public abstract void Fun();}
具体产品:不同产品继承不同抽象类。
/// <summary>/// 具体产品-美的电蒸锅/// </summary>public class MDElectric : Electric//这是美的电蒸锅,必须包含集团定义的电蒸锅的必备功能的同时也可以自己拓展{/// <summary>/// 具体的实现方法/// </summary>public override void Fun(){Console.WriteLine("美的电蒸锅蒸东西的功能是用大火蒸东西");}}/// <summary>/// 具体产品-苏泊尔电蒸锅/// </summary>public class SBRElectric : Electric//这是苏泊尔电蒸锅{public override void Fun(){Console.WriteLine("苏泊尔电蒸锅蒸东西的功能是用中火蒸东西");}}/// <summary>/// 具体产品-美的电饭煲/// </summary>public class MDRice : Rice//这是美的电饭煲{/// <summary>/// 具体的实现方法/// </summary>public override void Fun(){Console.WriteLine("美的电饭煲蒸东西的功能是用大火蒸东西");}}/// <summary>/// 具体产品-苏泊尔电饭煲/// </summary>public class SBRRice : Rice//这是苏泊尔电饭煲{public override void Fun(){Console.WriteLine("苏泊尔电饭煲蒸东西的功能是用中火蒸东西");}}
调用:
private void WTBtn_Click(object sender, EventArgs e){ElectricFactory electric;//创建了一个电器集团。electric = new MDFactory();//美的工厂var DZG = electric.GetElectric();//生产一个电蒸锅锅DZG.Fun();//这个锅实现具体的功能var DFB = electric.GetRice();//生产一个电饭煲DFB.Fun();//换个工厂electric = new SBRFactory();//苏泊尔工厂var DZG1 = electric.GetElectric();//生产一个电蒸锅锅DZG1.Fun();//这个锅实现具体的功能DZG1.AddFunction("苏泊尔");//看到电蒸锅大类(抽象产品)里可以加一个功能,让苏泊尔给这个锅加一个。var DFB1 = electric.GetRice();//生产一个电饭煲DFB1.Fun();}
上面实例可以看出创建一个工厂可以产出不同的产品。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
END........................................................................
相关文章:

C# 创建型设计模式----工厂模式
1 、什么是工厂模式 简单来说就是由一个对象去生成不同的对象,工厂模式是用工厂方法代替new操作的一种模式。工厂方法封装了多个相关联类的new方法,每次实例化这些类的时候不需要new多次,只需要调用工厂类的对应方法即可实例化这些类&#x…...

java中Scanner的nextLine和next方法
思考,输入1 2 3 4 5加上enter,输出什么 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int[][] m new int[2][2];for (int i 0; i < 2; i) {for (int j 0; j < 2;…...
2024年全国山洪径流模拟与洪水危险性评价技术及典型地区洪水淹没及损失分析
洪水淹没危险性(各种年遇型洪水淹没)是洪水损失评估、风险评估及洪水应急和管理规划等工作的重要基础。当前开展洪水危险性研究工作中的主要困难之一是水文资料稀缺,尤其是径流资料稀缺,既包括径流观测资料在时间上的短缺…...
CDC 同步数据需要的MySQL数据权限
授权命令如下: grant Replication client on *.* to username%; grant Replication slave on *.* to username%; flush privileges;...
Ubuntu20.04 更新Nvidia驱动 + 安装CUDA12.1 + cudnn8.9.7
一、概述 最近客户给了几台GPU服务器,长期放置落灰那种,然后想利用起来,所以上去看看了配置,系统是Ubuntu20.04,相关的驱动版本稍嫌老一些,所以需要更新Nvidia驱动,同时在安装CUDA和CUDNN,查看了显卡型号之后,打算使用onnxruntime进行推理,对比了版本,最后选择了CUD…...
算法自学 Lesson3 - 逻辑回归(LR)
目录 背景 一、适用数据集 1. 数据集选择 1.1 领域 1.2 数据集维度 1.3 记录行(样本数量) 2. 本文数据集介绍 3. 数据集下载 注意 二、逻辑回归的基本原理 1. 目的 2. Sigmoid 函数 3. 类别划分 4. 召回率 三、代码 1. 导入所需包&数…...

文件IO流
1.文件流概念 2.文件创建方式 3.常用方法 4.IO流原理 (1)InputStream,OutputStream, Reader, Writer四个都是抽象类,无法直接new, 需要由子类继承,然后new子类; (2)Reader和Writer…...

拥塞控制与TCP子问题(粘包问题,异常情况等)
拥塞控制 除了拥塞控制 以上的策越都是为了解决tcp 客户端和服务端提高效率,解决丢包的策略 但是拥塞控制是了为解决网络拥堵 出现了大面积丢包,我们发送方会判定是网络出现了问题? 丢包好解决,我们直接采用超时重传&#…...

stm32入门教程--DMA 超详细!!!
目录 简介 工作模式 1、数据转运DMA 2、ADC扫描模式DMA 简介 工作模式 1、数据转运DMA 这个例子的任务是将SRAM的数组DataA,转运到另一个数组DataB中,这个基本结构里的各个参数应该如何配置呢? 首先是外设站点和存储器站点的起始地址、…...
【使用Flask构建RESTful API】从零开始开发简单的Web服务!
使用Flask构建RESTful API:从零开始开发简单的Web服务 引言 随着Web应用程序的广泛使用,RESTful API已成为现代Web服务的核心技术之一。通过RESTful API,我们可以轻松地创建、读取、更新和删除(CRUD)数据,…...

用sdcc给51单片机编译C程序
学习单片机大部分人用的是Keil uVision,虽然好用,可大部分人用的是盗版,其实单片机程序小的话,完全可以用文本编辑器(推荐notepad)编写,然后用免费的sdcc来编译,下面介绍一下大致的过程。 sdcc…...
Java Lock LockSupport 源码
前言 相关系列 《Java & Lock & 目录》(持续更新)《Java & Lock & LockSupport & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Java & Lock & LockSupport & 总结》(学习总结/最新…...
Elasticsearch基础操作入门
阅前准备知识 学习 Elasticsearch (简称 ES) 的查询方式,建议从以下几个步骤入手: 理解 Elasticsearch 的基础概念 首先要了解 Elasticsearch 的核心概念,例如: Index(索引):相当于数据库中…...
跨域问题解决办法
跨域问题在Web开发中是一个常见的问题,特别是在前后端分离的开发模式下。以下是一些解决跨域问题的办法: 一、后端配置CORS(跨来源资源共享) CORS是一种机制,它使用额外的HTTP头来告诉浏览器一个网页的当前来源&…...
【数据结构与算法】力扣 23. 合并 K 个升序链表
题干描述 23. 合并 K 个升序链表 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入: lists [[1,4,5],[1,3,4],[2,6]] 输出: [1,1,2,3,4,4,5,6]…...

Java Lock CountDownLatch 总结
前言 相关系列 《Java & Lock & 目录》(持续更新)《Java & Lock & CountDownLatch & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Java & Lock & CountDownLatch & 总结》(学习总…...

vue+spreadjs开发
创建vue3项目 pnpm create vite --registryhttp://registry.npm.taobao.org安装spreadjs包 pnpm install "grapecity-software/spread-sheets17.1.7" "grapecity-software/spread-sheets-resources-zh17.1.7" "grapecity-software/spread-sheets-vu…...
针对初学者的PyTorch项目推荐
文章目录 1. MNIST手写数字识别2. CIFAR-10图像分类3. 图像风格迁移4. 文本生成(使用RNN)5. 简单的问答系统6. 简单的生成对抗网络(GAN)7. 简单的推荐系统 对于初学者来说,选择一些简单且具有教育意义的项目来实践PyTo…...
Helm Chart文件介绍
介绍(这个还没有完善 ,目前在找工作呢) Helm是Kubernetes的包管理器,类似于Ubuntu中的apt、CentOS中的yum或Python中的pip,可以快速查找、下载和安装软件包。Helm主要由客户端组件helm和服务端组件Tiller组成…...

1Panel 是新一代的 Linux 服务器运维管理面板
1Panel 是一款新一代的 Linux 服务器运维管理面板,旨在通过现代化的 Web 界面帮助用户轻松管理 Linux 服务器。它集成了主机监控、文件管理、数据库管理、容器管理等功能,并且支持多语言和国际化,包括英语、中文(繁体)和日语。以下是 1Panel …...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...