当前位置: 首页 > news >正文

设计模式-工厂方法模式

基于面向对象语言开发中,免不得需要创建对象。前面讲解的"单例模式"也是如此,不过是要创建唯一的对象。本文要讲述“工厂方法模式”是要封装创建对象的过程。工厂,也称之为“制造厂”,用于创建具体的产品直接提供给外界使用。其实,这就是对产品的创建过程的封装,外界需要产品,那就通过工厂提供的途径获取。反映到代码世界中,如果对象的创建过程复杂,需要封装对象创建过程时,我们可不通过一个“工厂”来封装这个过程呢。工厂的具体代码表现形式要看封装的粒度。这里封装的粒度包括方法(代码块)、类。这二者也分别代表着简单工厂方法模式、工厂方法模式

一、简单工厂模式

简单工厂模式,即是对象创建过程的封装粒度为方法或代码块(一般来说是方法)。如下为一个创建汽车对象的工厂示例:

/*** 汽车(抽象)接口*/
public interface Car {void start();void stop();
}
/*** 普通汽车实现类*/
public class CommonCar implements Car{@Overridepublic void start() {System.out.println("SUV 启动...");}@Overridepublic void stop() {System.out.println("SUV 停止...");}
}
/*** 创建汽车对象的工厂*/
public class CarFactory {public static Car createCarFactory() {return new CommonCar();}
}
public class Client {public static void main(String[] args) {// 获取对象Car caInstance = CarFactory.createCarFactory(); // 封装了所需对象创建的过程// 执行对象活动caInstance.start();caInstance.stop();}
}

在这里插入图片描述

简单工厂模式的实现方法及类图如上,用户端只需要通过CarFactory调用对应的方法即可获取对象,不需要感知到对象的创建过程。在大部分的业务代码中,还真就这种模式使用居多,比如某数据库客户端对象的获取、某加密算法对象获取等。但是,这么模式仅使用于比较简单的场景,如果业务上需要有多种数据库客户端、多种加密算法时,简单工厂方法模式就不能很好的胜任了。比如,上述场景的汽车对象会区分SUV及小轿车。那工厂方法模式就必须得改动,如改动为:

public static Car createCarFactory(String type) {if (type.equalsIgnoreCase("sedan")) {return new Sedan();     // 创建轿车的逻辑} else if (type.equalsIgnoreCase("suv")) {return new SUV();       // 创建SUV的逻辑} else {throw new IllegalArgumentException("无效的汽车类型" + type);}}

这样一改就有两个缺点:① 工厂方法逻辑完全改变了,也需要求客户端(上游依赖方)跟着改动;② 随着汽车种类的增多,if判断条件也会增加。多种类型汽车初始化逻辑存在于一个方法内部,非常不利于代码维护、调试。因此简单工厂模式的最大缺点就是不易扩展。进一步说,不易扩展的根因就在于将对象的创建逻辑封装与单一方法内部,不符合单一职责原则,也肯定不满足开闭原则了。
简单工厂模式的优点:

  • 避免对象创建过程的暴露
  • 实现简单,实用性高。
  • 适合创建对象种类少、规则相对稳定的业务。

简单工厂模式的优点:

  • 不符合单一职责原则,工厂创建对象的方法职责过重。
  • 不符合开闭原则,增加对象种类,需要改动原有工厂方法,甚至需要上游跟随改动。

二、工厂方法模式

为应用多种对象创建的需求,设计的工厂模式必须符合开闭原则。基于依赖倒置设计原则,工厂模块也应该有其抽象类,工厂与产品之间通过抽象类进行相互依赖。对于不同的抽象类用于创建不同的产品实例,因此,客户端仅需要感知创建那种对象使用那种工厂,和生活中例子一样,需要造汽车就找汽车工厂,需要衣服就找制服厂等。
还是以上述例子为例,如何实现SUV汽车、轿车的工厂,代码如下:
① 汽车接口

public interface Car {void start();void stop();
}

② 汽车具体实现类

public class SUV implements Car{@Overridepublic void start() {System.out.println("SUV 启动...");}@Overridepublic void stop() {System.out.println("SUV 停止...");}
}public class Sedan implements Car{@Overridepublic void start() {System.out.println("轿车 启动...");}@Overridepublic void stop() {System.out.println("轿车 启动...");}
}

③ 工厂接口

public interface Factory {Car createCarInstance();
}

④ 工厂具体实现类

public class SUVFactory implements Factory{@Overridepublic Car createCarInstance() {return new SUV();}
}public class SedanFactory implements Factory{@Overridepublic Car createCarInstance() {return new Sedan();}
}

⑤ 客户端

public class Client {public static void main(String[] args) {SUVFactory suvFactory = new SUVFactory();Car car4SUV = suvFactory.createCarInstance();   // 创建SUV汽车实例SedanFactory sedanFactory = new SedanFactory();Car car4Sedan = sedanFactory.createCarInstance();   // 创建SUV汽车实例}
}

在这里插入图片描述
工厂方法模式的示例代码及类图如上所示,这种设计模式解耦了工厂与产品的关系。高层与底层模块的关系符合依赖倒置原则,类之间的关系也符合迪米特法则。不同具体工厂类负责不同产品的实例创建,因此符合单一职责原则。从后续业务发展来看,即使后续增加产品类型,也只是增加新的产品类及对应的产品工厂类,不会改变已有的业务逻辑,因此这个设计方案是符合开闭原则的。
工厂方法模式的优点:

  • 避免对象创建过程的暴露
  • 符合开闭原则,易扩展
  • 适合创建对象种类多、规则相对不稳定的业务。

工厂方法模式的优点:

  • 实现负责,容易造成类的激增。

三、后注

本篇文章讲解了简单工厂模式以及工厂方法模式,这里我想说下工厂设计模式的宏观理解。简单的创建对象流程即使客户端直接创建对象,然后使用。
在这里插入图片描述
这个是最简单的创建并使用对象的方法,也是最常见的。但是问题在于,如果对象的创建过程及其复杂,难道要所有的调用方均复制一遍这块代码,增加了系统代码的臃肿程度。
因此,对于创建过程我们可以使用一种方式封装起来。封装在面向对象设计中就是为了复用代码,复用这套复杂创建逻辑的代码。封装的究极解决方案就是“加一层”,也是大部分情况都能很好解决问题的方案。何为加一层?就是在客户端与要创建对象的类之间加一层,将创建&初始化对象的逻辑封装到中间层-工厂。之后客户端要创建对象就找工厂,将客户端与对象复杂的创建过程进行解耦。【这里的基本思路为是谁导致的问题,找个人来负责解决它,即是重要逻辑细化】【如何更好使用单一职责原则?那块逻辑对业务影响大,那就需要一个方法、类或模块来负责之】
因此,创建对象这件事就仅是客户端和目标类之间的关系,中间有个工厂需要介入。
在这里插入图片描述
负责封装目标对象的工厂模式的具体表现要根据目标对象的复杂程度而定,复杂程度包括对象的种类数、对象业务规则的稳定性来确定。如果要创建的对象十分简单,那就使用简单工厂模式即可,反之则需要使用工厂方法模式来保证可扩展性。

提问:会不会存在工厂也比较多的时候呢?如何解决?

相关文章:

设计模式-工厂方法模式

基于面向对象语言开发中,免不得需要创建对象。前面讲解的"单例模式"也是如此,不过是要创建唯一的对象。本文要讲述“工厂方法模式”是要封装创建对象的过程。工厂,也称之为“制造厂”,用于创建具体的产品直接提供给外界…...

【Hammerstein模型的级联】快速估计构成一连串哈默斯坦模型的结构元素研究(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码实现 💥1 概述 在许多振动应用中,所研究的系统略微非线性。Hammerstein模型的级联可以方便地描述这样的系统。Hammerstein提供了一种基于指数正弦…...

「C 语言」extern关键字

在 C 语言中,关键字 extern 是用来告诉编译器,这个变量 OR 函数在其他文件中已有定义,可在当前文件中使用 当我们定义了一个全局变量 OR 函数时,它就已经具有了外部链接的属性,我们只需要通过在引用该变量的文件中用 …...

oracle单个用户最大连接数限制

项目经理反馈,现场已做了单个用户的最大连接数2000的限制,但数据库还是报无法连接,故障用户的连接数已3800多了。 查看日志报错如下 2023-07-20T13:07:57.79465308:00 Process m000 submission failed with error 20 Process m000 submiss…...

计算机网络最基础知识介绍

OSI和TCP/IP是很基础但又非常重要的知识,很多知识点都是以它们为基础去串联的,作为底层,掌握得越透彻,理解上层时会越顺畅。今天这篇网络基础科普,就是根据OSI层级去逐一展开的。 01 计算机网络基础 01 计算机网络的分类 按照网络的作用范围:广域网(WAN)、城域网(MA…...

接口测试进阶之数据模板

大家好久不见了。今天的文章将介绍jinja2模板在接口测试数据上的应用。 这几个月我在想,进阶系列要怎么写。 毕竟很多情况下,我觉得写技术文章和做培训一样,都会有两个结果: 1.是需要这些知识的人看不懂。 2.是看得懂的人不需要…...

Java中使用MySQL详解

1. 简介 在Java开发中,与数据库的交互是常见且重要的一部分。MySQL是一个广泛使用的关系型数据库管理系统,而Java作为一种强大的编程语言,提供了丰富的API和工具,使得与MySQL数据库的结合应用更加便捷和高效。 本篇博客将详细介…...

Docker安装Elasticsearch相关软件安装

Docker安装Elasticsearch相关软件安装 本文将介绍通过 Docker 的方式安装 Elasticsearch 相关的软件。 1、Docker安装Elasticsearch 1.1 搜索镜像 $ docker search elasticsearch $ docker search elasticsearch:7.12.11.2 拉取镜像 $ docker pull elasticsearch:7.12.11.…...

Ubuntu的安装与部分配置

该教程使用的虚拟机是virtuabox,镜像源的版本是ubuntu20.04.5桌面版 可通过下面的链接在Ubuntu官网下载:Alternative downloads | Ubuntu 也可直接通过下面的链接进入百度网盘下载【有Ubuntu20.04.5与hadoop3.3.2以及jdk1.8.0_162,该篇需要使…...

为什么 Splashtop 是更好用的 iOS 远程桌面应用

全球远程桌面软件市场最近达到19.2亿美元,表明使用任意设备实现随处远程控制越来越受欢迎。 近年来,企业的运营方式发生了重大改变,远程桌面软件已成为广泛使用的解决方案。Splashtop 是目前最好用的远程桌面工具之一,安全可靠且…...

[SQL挖掘机] - 字符串函数 - lower

介绍: lower函数是mysql中的一个字符串函数,其作用是将给定的字符串转换为小写形式。它接受一个字符串作为参数,并返回一个新的字符串,其中所有的字母字符均被转换为小写形式。 使用lower函数可以帮助我们在字符串处理中实现标准化和规范化…...

什么是Koala?

Koala 介绍 koala 是一个前端预处理器语言图形编译工具,支持 Less、Sass、Compass、CoffeeScript,帮助 web 开发者更高效地使用它们进行开发。跨平台运行,完美兼容 windows、linux、mac。 关键特性 多语言支持 支持 Less、Sass、CoffeeSc…...

阿里巴巴前端开发规范

前言 规范的目的是为了编写高质量的代码,让你的团队成员每天的心情都是愉悦的,大家在一起是快乐的。 现在软件架构的复杂性需要协同开发完成,如何高效地协同呢?无规矩不成方圆,无规范难以协同,比如&#xf…...

opencv-19 图像色彩空间转换函数cv2.cvtColor()

cv2.cvtColor() 函数是 OpenCV 中用于图像颜色空间转换的函数。它允许你将图像从一个色彩空间转换为另一个色彩空间。在 Python 中,你可以使用这个函数来实现不同色彩空间之间的转换。 函数的基本语法为: cv2.cvtColor(src, code[, dst[, dstCn]])参数…...

SpringCloudAlibaba微服务实战系列(二)Nacos配置中心

SpringCloudAlibaba Nacos配置中心 在java代码中或者在配置文件中写配置,是最不雅的,意味着每次修改配置都需要重新打包或者替换class文件。若放在远程的配置文件中,每次修改了配置后只需要重启一次服务即可。话不多说,直接干货拉…...

【Kafka源码走读】Admin接口的客户端与服务端的连接流程

注:本文对应的kafka的源码的版本是trunk分支。写这篇文章的主要目的是当作自己阅读源码之后的笔记,写的有点凌乱,还望大佬们海涵,多谢! 最近在写一个Web版的kafka客户端工具,然后查看Kafka官网,…...

Windows API遍历桌面上所有文件

要获取桌面上的图标&#xff0c;可以使用Windows API中的Shell API。以下是遍历桌面上所有文件的示例代码&#xff1a; #include <Windows.h> #include <ShlObj.h> #include <iostream> #include <vector> using namespace std;int main() {// 获取桌…...

【MySQL】基本查询(插入查询结果、聚合函数、分组查询)

目录 一、插入查询结果二、聚合函数三、分组查询&#xff08;group by & having&#xff09;四、SQL查询的执行顺序五、OJ练习 一、插入查询结果 语法&#xff1a; INSERT INTO table_name [(column [, column ...])] SELECT ...案例&#xff1a;删除表中重复数据 --创建…...

【Go语言】Golang保姆级入门教程 Go初学者介绍chapter1

Golang 开山篇 Golang的学习方向 区块链研发工程师&#xff1a; 去中心化 虚拟货币 金融 Go服务器端、游戏软件工程师 &#xff1a; C C 处理日志 数据打包 文件系统 数据处理 很厉害 处理大并发 Golang分布式、云计算软件工程师&#xff1a;盛大云 cdn 京东 消息推送 分布式文…...

mysql 自增长键值增量设置

参考文章 MySQL中auto_increment的初值和增量值设置_auto_increment怎么设置_linda公馆的博客-CSDN博客 其中关键语句 show VARIABLES like %auto_increment% set auto_increment_increment4; set auto_increment_offset2;...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...