c#中工厂模式详解
总体介绍:
工厂模式主要有三种类型:简单工厂、工厂方法和抽象工厂,该模式用于封装和管理对象的创建,是一种创建型模式。
万物皆对象,创建对象时必然需要new该对象,当需要更改对象时,需要把项目中所有地方都修改一遍,这显然违背了软件设计的开闭原则。
如果使用工厂来生成对象,那么我们只需要跟工厂打交道就可以了。如果要更新对象时,直接在工厂里更换即可。这就实现了对象解耦。
所以工厂模式主要用来解耦代码,将对象的创建和使用分离,使得代码更加灵活和可维护。
定义创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
适用于创建对象需要大量重复的步骤,或者需要依赖于其它对象的情况,它提供了一种方式来封装多个相关或依赖对象的创建逻辑。
(一)简单工厂基础介绍:
这是工厂模式的最基本形式,通过定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法模式,它属于类创建型模式,但不属于GOF23种设计模式。
简单工厂包含三大角色:
- 抽象产品(抽象类):定义了产品的规范,描述了产品的主要特征和功能。它是工厂类创建的所有对象的父类,封装了各种产品对象的共有方法。
- 具体产品(子类):继承抽象产品的子类,某个产品的具体实现类。
- 具体工厂(实例化对象类):它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;其可以被外界直接调用,创建所需的产品对象。
- 特性和功能:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
- 使用环境:当一个类不知道它所必须创建的对象的类的时候。
- 注意事项:每增加一个产品就需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度。
- 优点:一个调用者想创建一个对象,只要知道其名称就可以了。
- 缺点:增加新的产品需要修改工厂接口,违背了“开放-封闭原则”。
简单工厂创建方式:
- 首先定义一个抽象产品类。
1 /// <summary>
2 /// 该类是产品的父类即抽象产品,定义所有子类的共有属性和方法
3 /// </summary>
4 public abstract class Coffee
5 {
6 /// <summary>
7 /// 方便演示,只定义两个代表性方法。
8 /// </summary>
9 public abstract void GetName();
10
11 public void AddSugar()
12 {
13 Console.WriteLine("加糖");
14 }
15 }该类主要定义了产品的共有属性和方法,用于子类继承和实现。
- 其次定义每个产品的具体实现子类。
1 public class AmericanCoffee : Coffee
2 {
3 public override void GetName()
4 {
5 Console.WriteLine("我是一杯美式咖啡。");
6 }
7 }
8
9 public class LatterCoffe: Coffee
10 {
11 public override void GetName()
12 {
13 Console.WriteLine("我是一杯拿铁咖啡。");
14 }
15 }该类实现并继承自抽象类,如需增加产品可直接创建新的子类并继承自抽象类即可。
- 然后定义核心类,即工厂类。
1 public class CoffeeFactory
2 {
3 public CoffeeFactory()
4 {
5 }
6
7 /// <summary>
8 /// 简单工厂中必须要有一个方法来根据指定的逻辑创建实例
9 /// </summary>
10 /// <param name="fruitType"></param>
11 /// <returns></returns>
12 public static Coffee OrderCoffe(CoffeeEnum coffeeEnum)
13 {
14 switch (coffeeEnum)
15 {
16 case CoffeeEnum.AmericanCoffee:
17 return new AmericanCoffee();
18 case CoffeeEnum.LatterCoffe:
19 return new LatterCoffe();
20 }
21 return null;
22 }
23
24 public enum CoffeeEnum
25 {
26 AmericanCoffee,
27 LatterCoffe
28 }
29 }该类通过创建了一个枚举类型参数来选择需要创建的产品实例。
- 最后客户端调用。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //通过CoffeeFactory产品工厂创建了AmericanCoffee产品实例
6 Coffee coffee = CoffeeFactory.OrderCoffe(CoffeeFactory.CoffeeEnum.AmericanCoffee);
7 coffee.GetName();
8
9 //通过CoffeeFactory产品工厂创建了LatterCoffe产品实例
10 coffee = CoffeeFactory.OrderCoffe(CoffeeFactory.CoffeeEnum.LatterCoffe);
11 coffee.GetName();
12 coffee.AddSugar();
13 }
14 }根据客户端的选择条件来动态的实例化相关的类,
对于客户端来说,其去除了与具体产品之间的依赖。
简单工厂模式的缺点主要就是违背了开-闭原则,
在上面的 Demo 中,如果我要再增加一种产品。
那么,首先是定义一个新产品子类,让其继承自抽象类,然后呢,您还必须修改工厂类。
所以进而改进形成了工厂方法模式。
(二)工厂方法基础介绍:
这是一种更高级的工厂模式,它通过抽象接口或基类中的工厂方法来创建对象。
具体实现由子类负责,因此更加灵活。这种设计方式有利于实现开闭原则,即对扩展开放,对修改封闭。
简单工厂把全部的事情,在一个地方(类)全部处理完,而工厂方法却不同,
定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。
这样一来,扩展产品种类就不必修改工厂函数了,核心类就变成抽象类,工厂方法模式将生成具体产品的任务分发给具体的产品工厂。
也就是相当于工厂总部不生产产品了,交给下辖分工厂进行生产。
要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。
工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
工厂方法模式的主要角色:
抽象工厂:在抽象工厂类中声明了工厂方法,用于返回一个产品。提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
具体产品工厂:它是抽象工厂类的子类,实现了在抽象工厂中声明的工厂方法,完成具体产品的创建。并可由客户端调用,返回一个具体产品类的实例。
抽象产品:它是定义产品的接口,定义了产品的规范,描述了产品的主要特性和功能,是工厂方法模式所创建对象的公共父类。
具体产品:它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
缺点:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
工厂方法创建方式:
- 抽象产品类:
1 /// <summary>
2 /// 该类是产品的父类即抽象产品,定义所有子类的共有属性和方法
3 /// </summary>
4 public abstract class Coffee
5 {
6 /// <summary>
7 /// 方便演示,只定义两个代表性方法。
8 /// </summary>
9 public abstract void GetName();
10
11 public void AddSugar()
12 {
13 Console.WriteLine("加糖");
14 }
15 } - 具体产品类:
1 public class AmericanCoffee : Coffee
2 {
3 public override void GetName()
4 {
5 Console.WriteLine("我是一杯美式咖啡。");
6 }
7 }
8
9 public class LatterCoffe: Coffee
10 {
11 public override void GetName()
12 {
13 Console.WriteLine("我是一杯拿铁咖啡。");
14 }
15 } - 抽象工厂:
1 /// <summary>
2 /// 抽象工厂
3 /// </summary>
4 public abstract class CoffeeFactory
5 {
6 public abstract Coffee GetCoffee();
7 } - 具体产品工厂:
1 /// <summary>
2 /// 美式咖啡工厂
3 /// </summary>
4 public class AmericanFactory:CoffeeFactory
5 {
6 public override Coffee GetCoffee()
7 {
8 return new AmericanCoffee();
9 }
10 }
11
12 /// <summary>
13 /// 拿铁咖啡工厂
14 /// </summary>
15 public class LatterFactory : CoffeeFactory
16 {
17 public override Coffee GetCoffee()
18 {
19 return new LatterCoffe();
20 }
21 } - 客户端调用:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //首先创建一个美式咖啡工厂,只负责生产美式咖啡产品
6 CoffeeFactory coffeeFactory = new AmericanFactory();
7 //在美式咖啡工厂中生产一个美式咖啡产品
8 Coffee coffee = coffeeFactory.GetCoffee();
9 coffee.GetName();
10
11 //创建一个拿铁咖啡工厂,只负责生产拿铁咖啡产品
12 coffeeFactory = new LatterFactory();
13 //在工厂中生产一个拿铁咖啡产品
14 coffee = coffeeFactory.GetCoffee();
15 coffee.GetName();
16 //咖啡中加糖
17 coffee.AddSugar();
18 }
19 }通过客户端调用方式可以看出,不同产品的生产由原来的总工厂变为了各个分工厂去负责。
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。
(三)抽象工厂基础介绍:
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品,直接生成实例,这些工厂只生产同种类产品。
但是抽象工厂模式不同,抽象工厂模式并不直接生成实例, 而是用于对产品类簇的创建。
通俗点来讲就是:简单工厂和工厂方法模式的工作是生产产品,那么抽象工厂模式的工作就是生产工厂的。
是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
抽象工厂的最大好处在于交换产品系列非常方便,只需要改变具体工厂即可使用不同的产品配置。
抽象工厂模式的主要角色:
抽象工厂:在抽象工厂类中声明了多个工厂方法,用于返回多个产品。提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
具体产品工厂:它是抽象工厂类的子类,实现了在抽象工厂中声明的多个工厂方法,完成多个具体产品的创建。
抽象产品:它是定义一个产品的接口,定义了一个产品的规范,描述了一个产品的主要特性和功能。抽象工厂模式有多个抽象产品。
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
总的来说工厂方法模式一个工厂只生产一个产品,抽象工厂模式一个工厂生产多个产品,形成一个产品套餐,而多个工厂组成套餐系列。
抽象工厂创建方式:
- 抽象产品类,有多少个不同产品就创建多少个抽象产品类。
1 /// <summary>
2 /// 咖啡产品抽象类
3 /// </summary>
4 public abstract class Coffee
5 {
6 /// <summary>
7 /// 方便演示,只定义两个代表性方法。
8 /// </summary>
9 public abstract void GetName();
10
11 public void AddSugar()
12 {
13 Console.WriteLine("加糖");
14 }
15 }
16
17 /// <summary>
18 /// 甜点产品抽象类
19 /// </summary>
20 public abstract class Dessert
21 {
22 public abstract void GetName();
23 }实例中创建了两种产品,即咖啡和甜品。
- 具体产品类,不同产品继承不同抽象类。
1 public class AmericanCoffee : Coffee
2 {
3 public override void GetName()
4 {
5 Console.WriteLine("我是一杯美式咖啡。");
6 }
7 }
8
9 public class LatterCoffe: Coffee
10 {
11 public override void GetName()
12 {
13 Console.WriteLine("我是一杯拿铁咖啡。");
14 }
15 }
16
17 public class MatchaMousse: Dessert
18 {
19 public override void GetName()
20 {
21 Console.WriteLine("我是一块抹茶慕斯。");
22 }
23 }
24
25 public class Tiramisu: Dessert
26 {
27 public override void GetName()
28 {
29 Console.WriteLine("我是一块提拉米苏。");
30 }
31 }实例中定义了两种咖啡和两种甜点,咖啡为一个产品等级,甜点是另外一个产品等级。
- 抽象工厂类,有多少个系列就可以创建多少个抽象工厂类。本实例只创建了一个风味系列的工厂。
1 /// <summary>
2 /// 风味工厂
3 /// </summary>
4 public abstract class RelishFactory
5 {
6 //生产一杯咖啡
7 public abstract Coffee GetCoffee();
8 //生产一块甜点
9 public abstract Dessert GetDessert();
10 }实例中定义了一个系列的工厂,如果新增一个不同产品等级的奶茶,那就可以在风味工厂中生产一杯奶茶。同一种口味绑定为一个系列即一个抽象工厂。
- 具体工厂类,同一系列可以创建多个具体的工厂,负责同一系列下的不同产品出的创建。本实例创建了风味系列下的不同风味工厂的创建。
1 /// <summary>
2 /// 美式风味工厂
3 /// </summary>
4 public class AmericanRelishFactory : RelishFactory
5 {
6 public override Coffee GetCoffee()
7 {
8 return new AmericanCoffee();
9 }
10
11 public override Dessert GetDessert()
12 {
13 return new MatchaMousse();
14 }
15 }
16
17 /// <summary>
18 /// 意大利风味工厂
19 /// </summary>
20 public class ItalyRelishFactory : RelishFactory
21 {
22 public override Coffee GetCoffee()
23 {
24 return new LatterCoffe();
25 }
26
27 public override Dessert GetDessert()
28 {
29 return new Tiramisu();
30 }
31 }实例中创建了两种不同口味的工厂,选择对应口味的工厂,可以生产出对应口味的不同产品。
比如选择了美式口味工厂,该工厂可以生产出美式咖啡和抹茶慕斯。
实际上是该工厂将这两个不同等级的产品进行绑定,形成了一个产品族。
- 客户端调用:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //首先创建一种口味工厂
6 RelishFactory relishFactory = new AmericanRelishFactory();
7 //然后对应口味工厂中生产出对应口味的不同产品。
8 Coffee coffee = relishFactory.GetCoffee();
9 coffee.GetName();
10 Dessert dessert = relishFactory.GetDessert();
11 dessert.GetName();
12
13 Console.WriteLine("换一种口味");
14 relishFactory = new ItalyRelishFactory();
15 coffee = relishFactory.GetCoffee();
16 coffee.GetName();
17 dessert = relishFactory.GetDessert();
18 dessert.GetName();
19 }
20 }实例中可以看出创建了一个美式口味工厂,
该工厂就可以生产出符合该口味的不同产品。
其本质就是将相同口味的不同产品绑定成一个产品族,形成一个产品族工厂。
如果有多个产品族,那就创建多个产品族工厂就可以了。优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
总结:
简单工厂把全部的事情,在一个地方(类)全部处理完,
而工厂方法却不同,
其是通过创建一个框架,
然后让子类决定要如何实现。
而抽象工厂则是定义一个负责创建一组产品(也就是一个产品族)的接口,
抽象工厂的最大好处在于交换产品系列非常方便。
上述简单工厂模式和工厂方法模式都是直接生成实例,但是抽象工厂模式不同,抽象工厂模式并不直接生成实例, 而是用于对产品类族的创建。
通俗点来讲就是:简单工厂和工厂方法模式的工作是生产产品,那么抽象工厂模式的工作就是生产工厂的(产品类族)。
从上面可看到,简单工厂的优点就是我们只要传递正确的参数,就能获得所需的对象,而不需要关心其创建的具体细节。
工厂方法的优点就是让其子类决定具体实现,如日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等。
抽象工厂模式一般用于严格要求以面向对象思想进行开发的超大型项目中。
c#中工厂模式详解的更多相关文章
- JS设计模式——工厂模式详解
它的领域中同其它模式的不同之处在于它并没有明确要求我们使用一个构造器.取而代之,一个工厂能提供一个创建对象的公共接口,我们可以在其中指定我们希望被创建的工厂对象的类型. 简单工厂模式:使用一个类(通常 ...
- JAVA 设计模式之 工厂模式详解
一.简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类 的实例.属于创建型模式,但它不属于 GOF,23 种设计模式 (参考资料: ht ...
- 抽象工厂模式详解 —— head first 设计模式
项目实例 假设你有一家 pizza 店,你有很多种 pizza,要在系统中显示你所有 pizza 种类.实现这个功能并不难,使用普通方式实现: public class PizzaStore { Pi ...
- Java设计模式(5:设计模式的分类及工厂模式详解)
一.设计模式的分类 总的来说,设计模式可以分为三大类:创建型模式.结构型模式.行为型模式,具体如下图: 二.工厂模式 工厂模式分为简单工厂模式.工厂方法模式和抽象工厂模式.其中简单工厂模式并不属于23 ...
- java之简单工厂模式详解
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...
- 深入浅出的webpack构建工具---devTool中SourceMap模式详解(四)
阅读目录 一:什么是SourceMap? 二:理解webpack中的SourceMap的eval,inline,sourceMap,cheap,module 三:开发环境和线上环境如何选择source ...
- 代理模式详解:静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...
- Java中日志组件详解
avalon-logkit Java中日志组件详解 lanhy 发布于 2020-9-1 11:35 224浏览 0收藏 作为开发人员,我相信您对日志记录工具并不陌生. Java还具有功能强大且功能强 ...
- Extjs MVC开发模式详解
Extjs MVC开发模式详解 在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式, ...
- oracle中imp命令详解 .
转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...
随机推荐
- 基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发1-通用框架
基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发1-通用框架 Avalonia简介: Avalonia是.NET的一个跨平台UI框架,提供了一个灵活的样式系统,支持广泛的操作 ...
- ABP VNext添加全局认证(如何继承AuthorizeFilter)
前言 目前公司采用的开发框架是ABP VNext微服务框架 最近突然发现一个问题,ABP中如果控制器或服务层没有加 Authorize特性的话,则不会走身份认证,且不会认证Token 如图: 但是项目 ...
- python连接 Basler pylon相机遇到的问题
今天使用下图程序去连接相机 以下是摄像头IP参数 电脑IP参数 在确认电脑能够ping通相机的情况下 以及检查专用软件能否访问之后 依然遇到了以下错误 经过了多番调试之后发现即使能够ping通,子网掩 ...
- 2021-7-11 Vue的自定义指令简单实例
获取焦点简单实例,用Vue.directive(ps:指令)定义,命名不要是关键字,用v-加自定义指令名称调用,而内部用钩子函数inserted来实现 <!DOCTYPE html> &l ...
- Git:GitLab使用AD账户报错——remote: HTTP Basic: Access denied
错误原因 当第一次使用AD账户进入GitLab时,需要进行密码重置,之后重新登录并进行克隆操作即可.
- Redis从入门到放弃(5):事务
1.事务的定义 Redis的事务提供了一种"将多个命令打包, 然后一次性.按顺序地执行"的机制. redis事务的主要作用就是串联多个命令防止别的命令插队. 但是,事务并不具有传统 ...
- fastjson 1.2.80 漏洞浅析及利用payload
0x01 说明 在fastjson的1.2.80版本中可以通过将依赖加入到java.lang.Exception 期望类的子类中,绕过checkAuto. 0x02 简析 { "@type& ...
- GIT保存记录原理之commit对象
GIT 中提交对象非常的重要,我们通过它记录代码提交过程.进行文件保存.回退等操作,那么它是怎样帮助我们记录这些信息的呢?其实就是都保存在项目根目录的 .git 文件夹中. 新建空项目 ```gitD ...
- fastapi之helloworld
简介 以下简介来自官网描述: FastAPI是一个用于构建API的现代.快速(高性能)的web框架,使用Python3.6+并基于标准的Python类型提示. 关键特性: 快速:可与NodeJS和Go ...
- module.exports和exports,应该用哪个
在 Node.js 编程中,模块是独立的功能单元,可以在项目间共享和重用.作为开发人员,模块让我们的生活更轻松,因为我们可以使用模块来增强应用程序的功能,而无需亲自编写.它们还允许我们组织和解耦代码, ...