设计模式之工厂模式,史上最强,不服来辩!

article/2025/8/25 0:39:15

设计模式是对大家实际工作中写的各种代码进行高层次抽象的总结,如果设计模式没学会,抽象能力肯定就不会太强。常见的设计模式有 23 种,今天我们只聊最简单的工厂模式。

工厂模式是属于创建型模式的,通过工厂获取一个一个的新对象。说白了,工厂就是用来 new(创建)对象的,因此把它化分到创建型这一类中。

简单工厂模式

简单工厂模式,正如其名,和名字一样简单,非常简单。下面先看一段代码:

public class FoodFactory {public static Food makeFood(String name) {if ("kuaican".equals(name)) {Food kuaican = new KuaiCanFood();kuaican.setPrice(20.00);return kuaican;} if ("hamburger".equals(name)) {Food hamburger = new HamburgerFood();hamburger.setPrice(22.00);hamburger.setMeat("beef");return hamburger;} // ......return new RuntimeException("not food");}
}

需要注意的是,上面中的 KuaiCanFood 和 HamburgerFood 都继承自 Food。

简单地说,简单工厂模式通常就是这样,一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。

我们强调职责单一原则,一个类只提供一种功能,FoodFactory 的功能就是只要负责生产各种 Food。

Java 各种框架中,简单工厂模式是非常常见的,比如JedisConnectionFactory

Redis连接工厂

基本上 Java 中需要创建连接的框架,都是用了工厂模式。

工厂模式

简单工厂模式很简单,在一般情况下,它都能满足我们的需要。但是,在某些特殊场景,它就满足不了我们的需求了。还是拿 Redis 为例,Redis 有单机模式,主从模式,哨兵模式,Cluster 模式。每种模式的连接都不一样,因此我们需要引入多个工厂。

这种情况下,就需要引入多个简单工厂模式。比如:JedisConnectionFactoryJredisConnectionFactoryLettuceConnectionFactorySrpConnectionFactory等等。之所以需要引入工厂模式,是因为我们往往需要使用两个或两个以上的工厂。

还是以 Food 为例。

public interface FoodFactory {Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {@Overridepublic Food makeFood(String name) {if ("套餐A".equals(name)) {Food kuaican = new KuaiCanFood();kuaican.setPrice(20.00);kuaican.setName("快餐");return kuaican;} if ("套餐B".equals(name)) {Food mifan = new MiFanFood();mifan.setPrice(18.00);mifan.setName("五常大米");return mifan;} return null;}
}
public class AmericanFoodFactory implements FoodFactory {@Overridepublic Food makeFood(String name) {if ("套餐A".equals(name)) {Food hamburger = new HamburgerFood();hamburger.setPrice(22.00);hamburger.setName("hamburger");return hamburger;} if ("套餐B".equals(name)) {Food sandwich = new SandwichFood();sandwich.setPrice(25.00);sandwich.setName("三明治");return sandwich;} return null;}
}

其中,KuaiCanFood、MiFanFood、HamburgerFood、SandwichFood 都派生自 Food。

消费者调用:

public class Consumer {public static void main(String[] args) {// 先选择一个具体的工厂FoodFactory factory = new ChineseFoodFactory();// 由选择的工厂产生具体的对象,不同的工厂造出不一样的对象Food food = factory.makeFood("套餐A");}
}

虽然都是调用 makeFood("套餐A")  制作套餐 A,但是,不同的工厂生产出来的完全不一样。

第一步,我们需要选取合适的工厂,然后第二步基本上和简单工厂一样。

核心在于,我们需要在第一步选好我们需要的工厂。比如,我们有 FileFactory 接口,实现类有 AliyunOssFactory 和 TencentCosFactory,分别对应将文件写入阿里云 OSS 和腾讯云 COS 中。很显然,我们客户端或者消费者第一步就需要决定到底要实例化 AliyunOssFactory 还是 TencentCosFactory,这将决定之后的所有的操作。

工厂模式非常简单,我把他们都画到一张图上,希望大家能够看图就会:

工厂模式

现在会了还不是真会,一定要在实践代码中使用,不然过不了多久就会忘记!

抽象工厂模式

有了简单工厂模式,和工厂模式,为什么还有抽象工厂模式?

这就是当涉及到产品族的时候,就需要引入抽象工厂模式了。当一个产品族,存在多个不同类型的产品(比如我上面列举的 Redis 连接工厂)情况下,不同架构模式,选择不同的连接工厂的问题。而这种场景在业务开发中也是非常多见的,只不过可能有时候没有将它们抽象化出来。

Redis的连接工厂

RedisConnectionFactory的例子,我就不在多说了,建议spring-data-redis中的源码多看几遍。下面我再列举一个生活中的经典的例子,就是造一台手机。我们先不引入抽象工厂模式,看看怎么实现。

因为手机是由许多的构件组成的,我们将处理器 CPU 和主板 Board 进行抽象,然后 CPU 由 CpuFactory 生产,主板由 MainBoardFactory 生产。然后,我们再将 CPU 和主板搭配起来组合在一起,如下图:

抽象工厂模式

这个时候的如果需要手机产品,只需这样调用:

public class Phone {private Cpu cpu;private MainBoard mainBoard;public Phone(Cpu cpu, MainBoard mainBoard){this.cpu = cpu;this.mainBoard = mainBoard;}public static void main(String[] args) {// 得到华为的处理器CpuFactory KirinFactory = new HuaweiCpuFactory();Cpu cpu = KirinFactory.getCpu();// 得到华为的主板MainBoardFactory mainBoardFactory = new HuaweiMainBoardFactory();MainBoard mainBoard = mainBoardFactory.getMainBoard();// 组装手机CPU和主板Phone huaweiMate = new Phone(cpu, mainBoard);}
}

单独看处理器 CPU 工厂和主板工厂,它们分别是前面我们说的工厂模式。这种方式也容易扩展,因为要给手机加配件的话,只需要加一个 XxxFactory 和相应的实现即可,不需要修改现有的工厂。

但是,这种方式有一个问题,那就是如果苹果????家产的 CPU 和华为产的主板不能兼容使用,因此不能出现随意组合。这就是产品族的概念,它代表了组成某个产品的一系列配件的集合。

当涉及到这种产品族的问题的时候,就需要抽象工厂模式来支持了。我们不再定义 CPU 工厂、主板工厂、OS 工厂、显示屏工厂等等,我们直接定义手机工厂,每个手机工厂负责生产所有的设备,这样能保证肯定不存在兼容问题。

public interface PhoneFactory {Cpu getCpu();MainBoard getMainBord();Display getDisplay();
}
public class HuaweiPhoneFactory implements PhoneFactory {@Overridepublic Cpu getCpu() {return new HuaweiCpu();}@Overridepublic MainBoard getMainBord() {return new HuaweiMainBoard();}@Overridepublic Display getDisplay() {return new BoeDisplay();}
}
public class XiaomiPhoneFactory implements PhoneFactory {@Overridepublic Cpu getCpu() {return new HuaweiCpu();}@Overridepublic MainBoard getMainBord() {return new XiaomiMainBoard();}@Overridepublic Display getDisplay() {return new VisionoxDisplay();}
}

这种情况下,对于生产来说,不再需要单独挑选 CPU 厂商、显示屏厂商等,直接选择一家品牌工厂,品牌工厂会负责生产所有的东西,而且能保证肯定是兼容可用的。

public class Test {public static void main(String[] args) {// 第一步就要选定一个“大品牌工厂”PhoneFactory factory = new HuaweiPhoneFactory();// 从这个大厂设计制造CPUCpu cpu = factory.getCpu();// 从这个大厂生产手机主板MainBoard board = factory.getMainBord();// 从这个大厂生产手机显示屏Display boeDisplay = factory.getDisplay();// 生产一个华为 Mete 40 手机Phone huaweiMete40 = new Phone(cpu, board, boeDisplay);}
}

这样一个抽象工厂的代码和案例就讲完了,如果还有不懂的,我下次再拿我们现在生产项目中的案例给大家讲解!

最后总结一下,功能模式根据需求和功能的不同,你可以选择对应的简单工厂,普通工厂,和抽象工厂。抽象工厂看起来比较抽象,它暴露的问题也是显而易见的,比如我们要加个 NFC 模块,就需要修改所有的工厂,给所有的工厂都加上制造显示器的方法。这有点违反了对修改关闭,对扩展开放这个设计原则。但也不要完全照搬设计原则,毕竟有时候是需要打破原则,不是吗?比如在电商系统中的一些反范式设计等。


http://chatgpt.dhexx.cn/article/6J1p8sEs.shtml

相关文章

工厂设计模式

1、概念 工厂模式分三种:简单工厂模式、工厂方法模式、抽象工厂模式 简单工厂模式(Simple Factory Pattern):属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例&#xf…

设计模式之工厂模式(factory pattern)

工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建,是一种创建型模式。本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和…

sqlserver2008的SSMS连接sqlserver2016的时候提示‘索引超出了数组界限。’

解决:打sp3补丁。 http://www.microsoft.com/en-us/download/details.aspx?id44271

Matlab报错 :“位置 x 处的索引超出数组边界”

经常遇到“位置 x 索引超出数组边界”的报错,今天突然想到一个以前一直没有太留意的奇葩问题:这个报错里“位置x”指的是哪里?为什么一会是“位置3”,一会是“位置1”,有什么神秘的规矩吗? 善用搜索没发现…

.net reflector 反编译失败 索引超出了数组界限问题处理方法

.net reflector 反编译失败 索引超出了数组界限问题处理方法 时间:9个月前 作者:庞顺龙 浏览:177 [站内原创,转载请注明出处] 标签: Reflector .net reflector 反编译失败 索引超出了数组界限问题处理方法 de…

matlab索引超出数组边界且不提示数组边界的一种处理办法

问题如下。 相关代码如下: 问题原因如下: 将excel表另存为txt时选择的保存类型是Unicode文本(*.txt)。 处理办法。 将Unicode文本(*.txt)换成文本文件(制表符分隔)(*.txt)。 问题的表现如下: 利用matlab工作区发现…

最短路径算法详细介绍

据 Drew 所知最短路经算法现在重要的应用有计算机网络路由算法,机器人探路,交通路线导航,人工智能,游戏设计等等。美国火星探测器核心的寻路算法就是采用的D*(D Star)算法。 最短路经计算分静态最短路计算和…

[算法]-最短路径算法总结

Dijkstra最短路径算法 按路径长度的递增次序,逐步产生最短路径的贪心算法 基本思想:首先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从顶点v 到其它各顶点的最短路径全部求出为止。 时间复杂…

c++实现最短路径算法(Dijkstra算法)

0简介 Dijkstra算法是一种计算某一顶点到其余顶点最短路径的算法。它采用了贪心的策略,实现时使用了广度优先。这个算法常学常忘,因此写篇博客彻底解决它。 1计算步骤介绍 Dijkstra的计算步骤不难,如下 (1)设置一个集合表示已经标记过的节…

最短路径算法——dijkstra

dijkstra 前提:在一张图里,不能有权值为负数的边。 给你一个出发点,求出发点到所有结点的最短距离是多少?如果无法到达某个点,则到这个点的距离是正无穷(一般出现在有向图里面)。 举个&#…

最短路径算法详解

前言: 最短路径算法:用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。 例子: 暑期,你想要出门去旅游,但是在你出发之前,你想知道任意…

基于java最短路径算法的简单实现

一、我们先画一个可达路径图表: -1表示不可直达,0表示自己,其他整数表示长度或者权重 ABCDA012-1B-1015C-1-101D-1-1-10 用图形可表示为: 二、算法思路 1、先列出所有保存所有节点到可达节点的路径二维表 2、逐步寻找从起始节点到…

最短路径算法及应用

乘汽车旅行的人总希望找出到目的地的尽可能的短的行程。如果有一张地图并在图上标出每对十字路口之间的距离,如何找出这一最短行程?  一种可能的方法就是枚举出所有路径,并计算出每条路径的长度,然后选择最短的一条。那么我们很…

关于最短路径算法的理解

“最短路径算法:Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。​从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。” 我们解决最短路径问题,常用的是Dijkstra…

最短路径算法-----Dijkstra迪杰斯特拉算法

最近巩固一下算法,提高自己内力,网上看到查看到这篇介绍很详细的《Dijkstra迪杰斯特拉算法》,在这里转载记录一下。 1 前言 本章介绍迪杰斯特拉算法。和以往一样,本文会先对迪杰斯特拉算法的理论论知识进行介绍,然后给…

Dijkstra 最短路径算法 Python 实现

原文链接 问题描述 使用 Dijkstra 算法求图中的任意顶点到其它顶点的最短路径(求出需要经过那些点以及最短距离)。 以下图为例: 算法思想 可以使用二维数组来存储顶点之间边的关系 首先需要用一个一维数组 dis 来存储 初始顶点到其余各个顶…

神经网络最短路径算法,最短路径算法的原理

节约里程法求解最短路问题 你只要记住2点之间直线最短。节约里程法是用来解决运输车辆数目不确定的问题的最有名的启发式算法。1、节约里程法优化过程分为并行方式和串行方式两种。 核心思想是依次将运输问题中的两个回路合并为一个回路,每次使合并后的总运输距离…

最短路径算法及Python实现

最短路径问题 在图论中,最短路径问题是指在一个有向或无向的加权图中找到从一个起点到一个终点的最短路径。这个问题是计算机科学中的一个经典问题,也是许多实际问题的基础,例如路线规划、通信网络设计和交通流量优化等。在这个问题中&#…

图论:图的四种最短路径算法

目录: 1.DFS(单源最短路径算法) 例题1: DFS题目分析: 代码DFS: 2.Floyed(时间复杂度On^3) 1.应用场景: 2.解析算法: 核心代码1: 我的笔…

图的五种最短路径算法

本文总结了图的几种最短路径算法的实现:深度或广度优先搜索算法,费罗伊德算法,迪杰斯特拉算法,Bellman-Ford 算法。 1)深度或广度优先搜索算法(解决单源最短路径) 从起点开始访问所有深度遍历路径或广度优先路径,则到达终点节点的路径有多条,取其中路径权值最短的一…