C# 设计模式(1)——简单工厂模式、工厂模式、抽象工厂模式
1、前言
上一篇写了设计模式原则有助于我们开发程序的时候能写出高质量的代码(牵一发而不动全身),这个系列还是做个笔记温习一下各种设计模式,下面就看看简单工厂模式、工厂模式、抽象工厂模式。
2、简单工厂模式
其实我们可以这么理解简单工厂模式,就是专门负责生产对象的一个类,作用就是创建具体产品的实例。我们平时创建创建一个对象的时候通常都是new出来的,此时这个类就依赖与这个对象,说白了就是耦合度过高啦。需求变化的时候我们不得不去修改此类的源码。这时候就要用面向对象(OO)的思想去处理这个问题。把变化大的类封装起来,实现就不去动它。下面看个栗子,就生产、制造不同的汽车分析简单工厂模式的作用。
/// <summary>
/// 车 抽象类
/// </summary>
public abstract class Car
{
/// <summary>
/// 制造车--抽象方法
/// </summary>
public abstract void Make();
/// <summary>
/// 卖车--抽象方法
/// </summary>
public abstract void Sale();
} /// <summary>
/// 奥迪车
/// </summary>
public class ADCar : Car
{
public override void Make()
{
Console.WriteLine("制造了一辆奥迪车");
} public override void Sale()
{
Console.WriteLine("销售了一辆奥迪车");
}
}
/// <summary>
/// 奔驰车
/// </summary>
public class BCCar : Car
{
public override void Make()
{
Console.WriteLine("制造了一辆奔驰车");
} public override void Sale()
{
Console.WriteLine("销售了一辆奔驰车");
}
}
看客户端的调用
Car c = new ADCar();
c.Make();
c.Sale();
Console.WriteLine("\n");
Car b = new BCCar();
b.Make();
b.Sale();
我们可以看都是通过new一个ADCar 来创建一个实例, 想要奔驰的一样的要new一个出来 我想要n个那不是炸锅了。所以这里就创建一个车的简单工厂类。让这个工厂类来创建Car实例。这里的switch是C#的语法糖,感觉是不是有点香。
/// <summary>
/// 车的工厂类
/// </summary>
public class CarFactory
{
public static Car OpCar(string carName)
{
Car? car = null;
var ret = carName switch
{
"AD" => car=new ADCar(),
"BC" => car=new BCCar(),
_ => car=new ADCar()
};
return ret;
} } //客户端调用
Car cc = CarFactory.OpCar("AD");
cc.Make();
cc.Sale(); Car cc1 = CarFactory.OpCar("BC");
cc1.Make();
cc1.Sale();
这时候是不是就可以了,解决了客户端太过于依赖具体对象的问题,别急如果我再来一个宝马 就要还添加一个继承Car的BMCar 还要在 CarFactory的OpCar里面再加一个判断。按照开闭原则来说添加类没有啥影响,但是修改了CarFactory里面OpCar的代码就不符合开闭原则了。下面的工厂模式就专门解决这个问题。
3、工厂模式
在简单工厂模式中系统难以扩展且违背了开闭原则,这样使得简单工厂的实现逻辑过于复杂。工厂模式就是把具体创建类的实例中放在子工厂类中,工厂类不再负责所有产品的创建工厂类只提供创建实例。还是看上面的栗子我们加一个抽象工厂类出来,让不同的品牌去继承
/// <summary>
/// 车工厂类
/// </summary>
public abstract class CarFactory1
{
/// <summary>
/// 抽象方法
/// </summary>
public abstract Car OpCar();
}
/// <summary>
/// 奥迪工厂
/// </summary>
public class ADCarFactory1 : CarFactory1
{
public override Car OpCar()
{
return new ADCar();//在具体的工厂中实例化产品
}
}
/// <summary>
/// 奔驰工厂
/// </summary>
public class BCCarFactory1 : CarFactory1
{
public override Car OpCar()
{
return new BCCar();//在具体的工厂中实例化产品
}
} //客户端调用
CarFactory1 cf = new ADCarFactory1();
Car car = cf.OpCar();
car.Make();
car.Sale(); CarFactory1 cf2 = new BCCarFactory1();
Car car2 = cf2.OpCar();
car2.Make();
car2.Sale();
效果跟上面一样的,这里是不是就实现了新增一个宝马的话不用修改Factory里面的代码了只要在创建一个BMCarFactory1跟BMCar就可以了。我们要获取一个产品的时候我们就获取一个具体的工厂来实例它。 它是不是解决了简单工厂的不足也符合了开闭原则。问题也来了如果我不单单要销售车、卖车 搞大了我还要卖飞机卖火箭咋搞。这种不可能再去创建无数个工厂嘛。来看看抽象工厂模式。
4、抽象工厂模式
工厂模式它功能单一点只针对一个品牌,解决不了一系列的问题,卖火箭、卖飞机等等这些不同的品牌。如果我们在设计程序中显然工厂模式已经满足不了我们的需求了。抽象工厂模式就能很好的解决这个问题。这里我们还是新增一个抽象类,他提供制造、销售汽车的同事也提供制造销售飞机。实现方法只要实现自己品牌的的产品就可以了。
/// <summary>
/// 产品抽象类
/// </summary>
public abstract class PcFactory
{
/// <summary>
/// 车
/// </summary>
/// <returns></returns>
public abstract Car OpCar();
/// <summary>
/// 飞机
/// </summary>
/// <returns></returns>
public abstract Plan OpPlan();
}
/// <summary>
/// 奥迪pc工厂
/// </summary>
public class ADPcFactory : PcFactory
{
public override Car OpCar()
{
return new ADCar();
} public override Plan OpPlan()
{
return new ADPlan();
}
}
/// <summary>
/// 奔驰pc工厂
/// </summary>
public class BCPcFactory : PcFactory
{
public override Car OpCar()
{
return new BCCar();
} public override Plan OpPlan()
{
return new BCPlan();
}
} //客户端调用
PcFactory pf = new ADPcFactory();
Car adc = pf.OpCar();
Plan adc2 = pf.OpPlan();
adc.Make();
adc.Sale(); adc2.Make();
adc2.Sale(); PcFactory pf2 = new BCPcFactory();
Car abc = pf2.OpCar();
Plan abc2 = pf2.OpPlan();
abc.Make();
abc.Sale(); abc2.Make();
abc2.Sale();
我们可以看出抽象工厂跟工厂的区别就在于它能生产多种产品(车、飞机)工厂只能是单一的产品(车)。抽象类只注重创建的多个产品,不会关心具体的实现是什么。实现又是不通的产品工厂实现的。这样的话客户端也从具体的产品中解耦出来。
5、总结
简单工厂模式
优点:降低刻度段与具体产品的耦合度,实现new让工厂类去完成,也提高了代码的复用率。
缺点:违反了开闭原则系统扩展困难,而且工厂类集中了所有的业务逻辑一旦出问题整个系统都要受牵连。
工厂模式
优点:符合开闭原则新增功能不会区修改以前的代码。
缺点:产品功能单一写车的功能只能弄车,而不能加飞机、火箭的操作。
抽象工厂模式
优点:降低系统耦合度利于维护扩展,对于加系列产品符合开闭原则;
缺点:对于功能添加又不符合开闭原则了。看着是不是跟优点有冲突。这样说吧我现在要加一个宝马类不用修改业务逻辑添加一个BMCarFactory1跟BMCar就可以了。这是系列问题。如果我要加一个销毁的方法(之前就定义了制作、销售)那是不是还要在抽象类Car、Plan里面加一个抽象方法 继承里面的通通都要实现它。所以程序设计之初没有考虑到后面一个一个的改很麻烦。
一个系统要求不被所有客户端依赖到具体的实现这是所有工厂模式的应用的前提,这就要具体问题具体分析了。不可能说我要打印一个Holl Word还来搞设计模式嘛,高射炮打蚊子没有必要。各种模式都有好有坏,相对论就是这么说的,你得到一些的时候必然会失去一些,快乐要有悲伤作伴,雨过自然天晴吗。加了设计模式以后代码量肯定要上去的带给我们方便的同时也会增加风险。以前不解为啥要创建那么多项目,文件夹,现在想想就那么回事了。
PS:流年似水,岁月如歌,承受委屈是一种胸怀,接受误解是一种心怀,这个世界上失去什么东西都不可怕,惟一可怕的是失去你的心,失去你的勇气,只要你坚韧不拔地奋斗,只要你眼睛看向未来,生命就永远属于你,生命的辉煌也一定永远属于你。
C# 设计模式(1)——简单工厂模式、工厂模式、抽象工厂模式的更多相关文章
- java之设计模式工厂三兄弟之抽象工厂模式
[学习难度:★★★★☆,使用频率:★★★★★] 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工 ...
- 设计模式(一): abstract factory抽象工厂模式 -- 创建型模式
1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要 ...
- 设计模式C++学习笔记之七(AbstractFactory抽象工厂模式)
抽象工厂,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.对于工厂方法来说,抽象工厂可实现一系列产品的生产,抽象工厂更注重产品的组合. 看代码: 7.1.解释 main(),女 ...
- php设计模式课程---3、为什么会有抽象工厂方法
php设计模式课程---3.为什么会有抽象工厂方法 一.总结 一句话总结: 解决简单工厂方法增加新选择时无法满足面向对象编程中的开闭原则问题 1.什么是面向对象编程中的开闭原则? 应该对类的增加开放, ...
- 【设计模式】 模式PK:抽象工厂模式VS建造者模式
1.概述 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可.而建造者模式则是要求按 ...
- Android设计模式(十二)--抽象工厂模式
问题: 抽象工厂模式,是一个,狠恶心的模式,那么这个模式在Android有没实用到过呢? 1.定义: 抽象工厂模式:为创建一组相关或者是相互依赖的对象提供一个接口,而不须要指定他们的详细类. 2.使用 ...
- 系统架构-设计模式(适配器、观察者、代理、抽象工厂等)及架构模式(C/S、B/S、分布式、SOA、SaaS)(干货)
博客园首页是需要分享干货的地方,今天早上写的<HRMS(人力资源管理系统)-从单机应用到SaaS应用-系统介绍>内容下架了,所以我就按照相关规定,只分享干货,我把之前写完的内容整理发布上来 ...
- 简单理解C#中的抽象工厂模式是什么概念!
抽象工厂模式向客户端提供一个接口,使得客户端在不必指定具体类型的情况下,创建多个产品族中的对象.本文采取的仍然是接着以前的那个快餐店的例子.现在,快餐店经常良好,逐渐发展壮大,为了适合不同地方人的饮食 ...
- 【编程思想】【设计模式】【创建模式creational】抽象工厂模式abstract_factory
Python版 https://github.com/faif/python-patterns/blob/master/creational/abstract_factory.py #!/usr/bi ...
- 对象创建型模式------Abstract Factory(抽象工厂)
1. 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.2. 别名 Kit3. 动机 假设我们要开发一款游戏,当然为了吸引更多的人玩,游戏难度不能太大 ...
随机推荐
- 整数转化 牛客网 程序员面试金典 C++ Python
整数转化 牛客网 程序员面试金典 C++ Python 题目描述 编写一个函数,确定需要改变几个位,才能将整数A转变成整数B. 给定两个整数int A,int B.请返回需要改变的数位个数. 测试样例 ...
- oracle 定时任务增、删、改、查
增: 创建一个计划任务 begin sys.dbms_job.submit(job=>:job, what=>'要定时执行的存储过程名:',--例如:包名.存储过程名; 记得写分号 ne ...
- 使用Charles 弱网测试
打开Charles->Proxy→Throttle Settings 1.可以选择不通的网络类型,对于网络的配置一般修改下上行下行即可 2.网络设置各字段解释 bandwidth -- 带宽,即 ...
- mysql根据条件决定是否插入数据
这个问题其实分两个方面: 1.根据表的主键决定数据是否插入. 2.根据表的非主键决定是否插入. 假设有表DOC_INFO(医生表),联合主键HOS_ID(医院代码),DEPT_CODE(科室代码),D ...
- Java学习(十八)
学习了Web中的单位. 像素是网页中最常用到的单位,一个像素是屏幕中的一个小点. 不同显示器一个像素的大小也不同,像素越小,显示效果越好. 也可以用百分比的方式: <!DOCTYPE html& ...
- 美妙绝伦面向node引用-zico图标(逐浪矢量全真图标)1.9发布
15年前,那个农村小伙初入广告行业被讥笑没有审美 于是他狠下决心,积极研发,缔就技术之核, 再后来,那些PPT和美工er们随便怎么自好,无法让其心怵. 因为他是中华人民共和国唯一具备web.cms.o ...
- SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(3)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节针对我们的重试进行测试 验证针对可重试的方法响应超时异常重试正确 我们可以通 ...
- python爬取豆瓣电影第一页数据and使用with open() as读写文件
# _*_ coding : utf-8 _*_ # @Time : 2021/11/2 9:58 # @Author : 秋泊酱 # @File : 获取豆瓣电影第一页 # @Project : 爬 ...
- IDEA下载 使用快捷方式 以及一些小教程
IDEA下载 使用快捷方式 以及一些小教程 Idea下载 网址:链接: https://pan.baidu.com/s/1xRr3mhM6_VDHqC_w0F1MjQ 提取码: 6ypi 下载,安装方 ...
- Maven 依赖调解源码解析(一):开篇
本文是系列文章<Maven 源码解析:依赖调解是如何实现的?>第一篇,主要做个开头介绍.并为后续的实验做一些准备.系列文章总目录参见:https://www.cnblogs.com/xia ...