09.简单工厂模式与工厂方法模式

道生一,一生二,二生三,三生万物。——《道德经》

在这里插入图片描述
最近小米新车亮相的消息可以说引起了不小的轰动,我们在感慨SU7充满土豪气息的保时捷设计的同时,也深深的被本土品牌的野心和干劲所鼓舞。
今天我们就接着这个背景,开启造车的终极幻想,尝试拆解一下工厂模式中最基础的两部分:简单工厂模式和工厂方法模式。


一言

简单工厂模式:定义一个创建对象的类,由它来封装实例化对象的行为代码。
工厂方法模式:将对象实例化推迟到子类。


为什么要用工厂模式

Wayne造车

如果现在有一个需求,要我们模拟一段造车的代码,你想怎么做?
首先自然是分析需求:

  1. 既然我们要造车,那车的种类必然很多(油车?电车?核动力?!)
  2. 造车的工序我们暂时就粗暴的认为只有准备材料、加工、组装和测试四个步骤
  3. 造好了车,我们还需要通过4S店卖出去

三寸反骨

三条需求刚刚讲完,反骨仔立马站了起来:“这也太简单了!我来!”
于是他这样实现了需求:
首先他清醒的将车做成了抽象:

代码实现(反例)

public abstract class Car {protected String name;//名字//准备原材料,不同的汽车材料不同,所以做成抽象方法public abstract void prepare();public void process(){//加工System.out.println(name+" processing");}public void assemble(){//组装System.out.println(name+" assemble");}public void check(){//测试System.out.println(name+" check");}public void setName(String name) {this.name = name;}
}

然后是车具体的实现:

public class OilCar extends Car{@Overridepublic void prepare() {System.out.println("准备优秀的内燃机");}
}
public class EleCar extends Car{@Overridepublic void prepare() {System.out.println("准备优秀耐用的电池");}
}

最后是4S店

public class FourS {//构造器public FourS() {Car car = null;String orderType;do {orderType=getType();System.out.println("==============================");if (orderType.equals("ele")){car = new EleCar();car.setName("新能源汽车");}else if (orderType.equals("oil")){car = new OilCar();car.setName("燃机汽车");}else {break;}car.prepare();car.process();car.assemble();car.check();}while (true);}private String getType(){try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("==============================");System.out.println("input car type");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();}return "";}
}

不得不说,反骨仔确实有所成长,不再是那个100%的毛躁汉子了,但是这种设计是否存在问题?
我们先看下运行的结果:
在这里插入图片描述
业务的实现自然是没有问题的,实现过程也非常容易理解,然后一切的一切发展的都很顺利,我们的车一经上市就大受欢迎,在各方面都是遥遥领先。于是我们决定,扩展业务,“多开几家4S店,再狠狠的赚他一笔,初步预估先开1000家店吧,靓仔啊,你去把这个事情落实一下。奥,对了,你们这个项目现在发展前景非常好,我们已经在和奔驰、宝马、宾利、法拉利等老牌的汽车公司展开了深度合作,以后可能还要把他们的品牌融合到我们的产品中…”。
反骨仔看着自己的代码,汗流浃背了。
可能有的同学已经看到了问题的关键:
在这里插入图片描述
这种设计从根本上违反了OCP原则,每一次小的扩展就会更改大量代码。
有的同学可能会说,我ctrl CV 大法包治百病,那如果我们后面真的在核动力汽车领域有了突破,这部分扩展的代码是不是要改一千多次?
所以说,修改代码并非不可接受,但是如果我们在其它地方也有创建Car,就意味着这些地方都要修改,而创建Car的地方往往有很多处。


基于简单工厂模式的优化

思路分析

好了,我们已经发现了问题下一步就是如何解决这个问题了。
在思路上,我们可以尝试把创建Car对象封装在一个类中,这样我们有新的Car种类时,只需要修改该类即可,其它创建Car对象的代码就不需要修改了。这其实就是简单工厂模式的基本思路。
在这里插入图片描述

核心代码

public class FourS1 {Car car = null;public FourS1(){setFactory();}public void setFactory(){String orderType="";do{orderType = getType();System.out.println("==============================");car = SimpleFactory.createCar(orderType);if (car!=null){car.prepare();car.process();car.assemble();car.check();}else {System.out.println("订购汽车失败");break;}}while (true);}//可以获取客户希望订购的披萨种类private String getType(){try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("==============================");System.out.println("input pizza type");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();}return "";}
}

结束了吗

当然没有,我们看似通过简单方法模式解决了大部分的核心问题,但是却忽略了“最新消息”里最致命的那句:“奥,对了,你们这个项目现在发展前景非常好,我们已经在和奔驰、宝马、宾利、法拉利等老牌的汽车公司展开了深度合作,以后可能还要把他们的品牌融合到我们的产品中…”
也就是说,我们后续要求的输出是奔驰的燃机汽车、宝马的燃机汽车、宝马的新能源汽车、奔驰的核动力汽车…
反观简单工厂模式,是否有实力接得住这一波需求?
其实硬要接也不是接不住,无非是多几个SimpleFactory。但是实际操作起来必然很难维护。严格意义上讲,采用简单工厂模式硬接这种需求实际上也是违反OCP原则的。


基于工厂方法模式的优化

思路分析

当与各大品牌合作之后,造车过程似乎变得复杂了起来。首先奔驰和宝马是想和我们合作,而他们之间并没有展开合作,这意味着我们要为他们定制不同的4S店和造车工厂。
在这里插入图片描述

核心代码

public abstract class AbsFourS {public abstract Car createPizza(String orderType);public AbsFourS() {Car car = null;String orderType;do {orderType=getType();System.out.println("==============================");car=createPizza(orderType);car.prepare();car.process();car.assemble();car.check();}while (true);}private String getType(){try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("==============================");System.out.println("input car type");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();}return "";}
}
public class BenzWayne4s extends AbsFourS {@Overridepublic Car createPizza(String orderType) {Car car = null;if(orderType.equals("ele")){car = new BenzEleCar();car.setName("奔驰与Wayne联名推出的新能源汽车");}else if (orderType.equals("oil")){car = new BenzOilCar();car.setName("奔驰与Wayne联名推出的内燃机汽车");}return car;}
}
public class BmwWayne4s extends AbsFourS {@Overridepublic Car createPizza(String orderType) {Car car = null;if(orderType.equals("ele")){car = new BMWEleCar();car.setName("宝马与Wayne联名推出的新能源汽车");}else if (orderType.equals("oil")){car = new BMWEleCar();car.setName("宝马与Wayne联名推出的内燃机汽车");}return car;}
}

测试结果

在这里插入图片描述
在这里插入图片描述


我们在前面用了大量的篇幅介绍了简单工厂模式和工厂方法模式。记得我在上一篇介绍建造者模式时,卖了个关子,就是关于建造者模式和抽象工厂模式的区别。
抽象工厂模式可以将简单工厂模式和工厂方法模式的优势整合起来,它的理念是基于简单工厂模式和工厂方法模式的,这也正是我花了大量篇幅介绍它们的原因。
抽象工厂模式实现对产品家族的创建,一个产品家族是具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
也就是说:
• 建造者模式比较关注 产品的 “组装过程”;
• 抽象工厂模式只关注什么工厂生产了什么产品;
这一点,在我下周继续拆解抽象工厂模式之后,我们可以一起再来体会一下。


关注我,共同进步,每周至少一更。——Wayne

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019年认证杯SPSSPRO杯数学建模B题(第一阶段)外星语词典全过程文档及程序

2019年认证杯SPSSPRO杯数学建模 基于方差分布的方法对未知语言文本中重复片段的自动搜索问题的研究 B题 外星语词典 原题再现: 我们发现了一种未知的语言,现只知道其文字是以 20 个字母构成的。我们已经获取了许多段由该语言写成的文本,但…

Phoenix基本使用

1、Phoenix简介 1.1 Phoenix定义 Phoenix是HBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据。 1.2 Phoenix特点 容易集成:如Spark,Hive,Pig,Flume和Map Reduce。性能…

golang并发安全-select

前面说了golang的channel, 今天我们看看golang select 是怎么实现的。 数据结构 type scase struct {c *hchan // chanelem unsafe.Pointer // 数据 } select 非默认的case 中都是处理channel 的 接受和发送,所有scase 结构体中c是用来存储…

C++模板——(4)C++泛型编程与标准模板库简介

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言​📝 勤奋,机会,乐观…

海量数据处理数据结构之Hash与布隆过滤器

前言 随着网络和大数据时代的到来,我们如何从海量的数据中找到我们需要的数据就成为计算机技术中不可获取的一门技术,特别是近年来抖音,快手等热门短视频的兴起,我们如何设计算法来从大量的视频中获取当前最热门的视频信息呢&…

Vue3:使用解构赋值来读取对象里的键-值对(值也是对象)

一、前言 在Vue3中,想要读取一个对象的“键—值”对(值也是一个对象),数据格式如下: {1:{courseName: 课程1, study: 951526, visit: 3785553},2:{courseName: 课程2, study: 181630, visit: 380830}&…

VCG 网格曲率计算

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Mesh曲率特征通常指的是在三维几何网格(Mesh)上计算的曲率相关的一系列特征,包括主曲率、高斯曲率、平均曲率等。这些曲率特征提供了对Mesh表面形状的详细描述,对于表面形状分析、形状比较和几何建模等领域非常…

【UML】第16篇 活动图

目录 一、什么是活动图 二、应用场景: 三、绘图符号的说明: 四、语法: 五、例图 六、建模的流程 6.1 对业务流程建模时 6.2 对用例进行活动图建模时 一、什么是活动图 活动图(Activity Diagram)是UML中用于描…

msckf-vio 跑Euroc数据集,并用evo进行评估

所需材料: Euroc数据集主页:https://projects.asl.ethz.ch/datasets/doku.php?idkmavvisualinertialdatasetsevo评估工具代码:https://github.com/MichaelGrupp/evo向msckf-vio中添加保存位姿的代码,可参考https://blog.csdn.ne…

网络安全复习--简答整理

-----------------------------------------------------教材如上图------------------------------------------------------------ 1.对称加密和非对称加密各有什么特点?加密解密过程中有什么区别?优点P38【考】 对称加密的特点:在针对同一…

JDBC多表联查

JDBC多表联查 在单一表进行查询时&#xff0c;只需要对表中的单个字段进行解析即可&#xff1b;例如下面代码&#xff1a; Overridepublic List<ClassBean> selectAllDao() {List list new ArrayList();try {String sql "select * from class";rs select(s…

Spring MVC 参数接收

参数接收 Springmvc中&#xff0c;接收页面提交的数据是通过方法形参来接收&#xff1a; 处理器适配器调用springmvc使用反射将前端提交的参数传递给controller方法的形参 springmvc接收的参数都是String类型&#xff0c;所以spirngmvc提供了很多converter&#xff08;转换器…

网络名称解读 -入门5

WAN: Wide Area Network(跨区域&#xff09;&#xff0c;LAN&#xff1a; Local Area NetworkWAN MAC&#xff0c; 用来连接上级网络&#xff0c; LAN MAC&#xff0c; 用于内部网路。 LAN & WAN 3.1&#xff0c;LAN表示子网&#xff0c;通过掩码来筛选子网内主机数量&…

Unity Delaunay三角剖分算法 动态生成

Unity Delaunay三角剖分算法 动态生成 Delaunay三角剖分Delaunay三角剖分 定义Delaunay 边Delaunay 空圆特性 Delaunay 三角形Delaunay 最大化最小角特性 Delaunay 三角形特征Delaunay 算法Delaunay Lawson算法Delaunay Bowyer-Watson算法 Unity Delaunay三角剖分 应用Unity 工…

Vulnhub-VULNCMS: 1渗透

文章目录 一、前言1、靶机ip配置2、渗透目标3、渗透概括 开始实战一、信息获取二、获取shell三、获取密码文件四、提权 一、前言 由于在做靶机的时候&#xff0c;涉及到的渗透思路是非常的广泛&#xff0c;所以在写文章的时候都是挑重点来写&#xff0c;尽量的不饶弯路。具体有…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -后端鉴权拦截器实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

邻接矩阵、可达性矩阵、完全关联矩阵、可达性矩阵的计算

邻接矩阵&#xff1a;很简单&#xff0c;就是两个点有关系就是1&#xff0c;没有关系就是0 可达性矩阵&#xff1a;非常简单&#xff0c;两点之间有路为1&#xff0c;没有路为0 可发行矩阵的计算&#xff1a;有n个元素&#xff0c;初始可达性矩阵为A&#xff0c;那么最终的矩阵…

K2P路由器刷OpenWrt官方最新版本固件OpenWrt 23.05.2方法 其他型号的智能路由器OpenWrt固件刷入方法也基本上适用

最近路由器在开机时总出问题,于是就那他来开刀,直接刷一个OpenWrt官方最新版本的固件, 刷其他第三方的固件总是觉得不安全, 而且很多第三方固件都带了些小工具,始终会有安全隐患, 而且占用内存空间太多,本来这个东西就没有多少内存,于是就干脆刷一个官方的原始固件(才6.3M, 相…

使用numpy处理图片——滤镜

大纲 3维数组切分打平重组法深度切分法 3维数组堆叠 我们在用手机拍照片时&#xff0c;往往会对照片进行滤镜处理&#xff0c;从而让照片更加美观。本文我们将实现几种滤镜效果——去除所有像素中的某一种原色&#xff0c;形成只有红绿、红蓝和绿蓝原色的照片。 为了突出色彩丰…

怎么投稿各大媒体网站?

怎么投稿各大媒体网站&#xff1f;这是很多写作者及自媒体从业者经常面临的问题。在信息爆炸的时代&#xff0c;如何将自己的文章推送到广大读者面前&#xff0c;成为了一个不可避免的挑战。本文将为大家介绍一种简单有效的投稿方法——媒介库发稿平台发稿&#xff0c;帮助大家…