工厂方法模式(Factory Method)
工厂方法模式就是定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子工厂类来决定该实例化哪一个类。
Define an interface for creating an object, but let subclasses decide which class to instantiate.
The Factory method lets a class defer instantiation it uses to subclasses.
结构设计
工厂方法模式包含如下角色:
Product,抽象产品,用来定义工厂方法所创建的对象的接口。
ConcreteProduct,具体产品,用来实现Product的接口。
Factory,抽象工厂,负责声明工厂方法,该方法返回一个Product类型的对象。
ConcreteFactory,具体工厂,用来实现Factory声明的工厂方法。
工厂方法模式类图表示如下:

伪代码实现
接下来将使用代码介绍下工厂方法模式的实现。
// 1、定义产品(Product)抽象类(也可以是基类),对产品接口进行声明
public abstract class Product {abstract void function();
}
// 2、定义具体产品(Concrete Products),产品接口的不同实现
public class ConcreteProductA extends Product {@Overridepublic void function() {System.out.println("---------do some thing in a ConcreteProductA instance---------");}
}
public class ConcreteProductB extends Product {@Overridepublic void function() {System.out.println("---------do some thing in a ConcreteProductB instance---------");}
}
// 3、产品工厂(Product Factory)抽象类或基类,声明返回产品对象的工厂方法。该方法的返回对象类型必须与产品接口相匹配。
// 可以将工厂方法声明为抽象方法,强制要求每个子类以不同方式实现该方法。或者,在基础工厂方法中返回默认产品类型。
// 注意,该类最主要的职责并不是创建产品。 一般来说, 产品工厂类包含一些与产品相关的核心业务逻辑。工厂方法将这些逻辑处理从具体产品类中分离出来。
public abstract class ProductFactory {/*** 生产产品*/abstract Product create();
}
// 4、具体产品工厂(Concrete Product Factories)重写基础工厂方法, 使其返回不同类型的产品。
// 注意, 并不一定每次调用工厂方法都会创建新的实例。工厂方法也可以返回缓存、对象池或其他来源的已有对象。
public class ProductFactoryA extends ProductFactory {@Overridepublic Product create() {System.out.println("create ProductA");return new ConcreteProductA();}
}
public class ProductFactoryB extends ProductFactory {@Overridepublic Product create() {System.out.println("create ProductB");return new ConcreteProductB();}
}
// 5、客户端调用
public class FactoryMethodClient {public void foo() {// (1) 实例化产品工厂ProductFactory productFactoryA = new ProductFactoryA();// (2) 生产产品Product productA = productFactoryA.create();// (3) 使用产品productA.function();ProductFactory productFactoryB = new ProductFactoryB();Product productB = productFactoryB.create();productB.function();}
}
适用场景
在以下情况下可以考虑使用工厂方法模式:
(1) 如果无法预知对象确切类别及其依赖关系时,可使用工厂方法。
工厂方法将创建产品的代码与实际使用产品的代码分离,从而能在不影响其他代码的情况下扩展产品创建部分代码。
例如,如果需要添加一种新产品,则只需要开发新的产品工厂子类,然后重写其工厂方法即可。
(2) 如果希望用户能扩展软件库或框架的内部组件,可使用工厂方法。
继承是扩展软件库或框架默认行为的最简单方法。但是,当使用子类替代标准组件时,框架如何辨识出该子类?解决方案是将各框架中构造组件的代码集中到单个工厂方法中,并在继承该组件之外允许任何人对该方法进行重写。
(3) 如果希望复用现有对象来节省系统资源,而不是每次都重新创建对象,可使用工厂方法。
在处理大型资源密集型对象(如数据库连接、文件系统和网络资源等)时, 经常需要服用现有对象已节省资源。
正常情况下,为实现现有对象的复用,其处理流程一般如下:
首先,创建存储空间来存放经创建的对象。
然后,在外部请求对时,将优先在对象池中搜索可用对象。如果存在则立即返回该对象。
如果没有可用对象,则创建并返回该新对象(并将其添加到对象池中)。
为避免上述代码不会因为重复而污染程序(对象的创建场景可能很多),可以将这些代码放在试图重用的对象类的构造函数中。
但是从定义上来讲,构造函数始终返回的是新对象,其无法返回现有实例。针对这种既需要一个能够创建新对象,又可以重用现有对象的场景,工厂方法是最佳选择。
优缺点
工厂方法模式有以下优点:
(1) 将创建产品的代码与实际使用产品的代码分离(解耦),避免产品创建工厂和实际产品之间的紧耦合。
(2) 单一职责原则。产品创建代码放在单独的类里,从而使得代码更容易维护。
(3)开闭原则。无需更改客户端调用代码, 就可以在程序中引入新的产品类型。
但是工厂方法模式也存在以下缺点:
(1) 应用工厂方法模式需要引入许多新的子类,代码会因此变得更复杂。最好的情况是将该模式引入产品类的现有层次结构中(将工厂类组合到产品类里)。
(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到反射等技术,增加了系统的实现难度。
参考
https://www.edrawsoft.cn/ 亿图图示
《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/factory_method.html 工厂方法模式
https://refactoringguru.cn/design-patterns/factory-method 工厂方法模式
https://blog.csdn.net/ShuSheng0007/article/details/86636494 秒懂设计模式之工厂方法模式
https://www.runoob.com/design-pattern/factory-pattern.html 工厂模式
相关文章:
工厂方法模式(Factory Method)
工厂方法模式就是定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子工厂类来决定该实例化哪一个类。 Define a…...
js如何将图片转成BASE64编码,网页跟uniapp开发的app的区别?
Base64是一种用64个字符来表示任意二进制数据的方法,这篇文章主要为大家介绍了如何实现将图片转为base64格式,感兴趣的小伙伴可以学习一下 前言 前段时间在写我的VUE全栈项目的时候,遇到要把前端的照片上传到后端,再由后端存到数…...
1400*C. Computer Game
Example input 6 15 5 3 2 15 5 4 3 15 5 2 1 15 5 5 1 16 7 5 2 20 5 7 3 output 4 -1 5 2 0 1 解析: k个电, 第一种为 k>a 时,只玩游戏 k-a; 第二种,k>b,一边玩一边充电 k-b 问完成n轮游戏的情况下,优先第…...
windows10访问Ubuntu 18.04共享目录(已验证)
1、Ubuntu 18.04安装samba sudo apt-get install samba 2、创建一个共享目录文件夹,并设置777权限 ubt1804是用户名 mkdir/home/ubt1804/lsk sudo chmod 777 /home/ubt1804/lsk 3、添加用户及密码 sudo smbpasswd -a [用户名] 比如用户名为test sudo sm…...
Linux安装redis执行make命令报错:gcc not found和*** [adlist.o] Error 1
目录 第一章、问题分析与解决1.1)报错11.2)报错2 友情提醒 先看文章目录,大致了解文章知识点结构,点击文章目录可直接跳转到文章指定位置。 第一章、问题分析与解决 1.1)报错1 报错问题1:gcc: Command n…...
R语言glmnet包详解:横截面数据建模
R语言glmnet包详解:横截面数据建模 glmnet适用的模型glmnet建模补充glmnet适用的模型 glmnet程序包即适用于线性模型,也适用于添加惩罚项项的线性模型。如果数据中的变量个数大于样本量并且想用线性模型解决问题,那么glmnet再合适不过了! 根据glmnet函数中参数family的指定…...
LeetCode257. 二叉树的所有路径
257. 二叉树的所有路径 文章目录 257. 二叉树的所有路径一、题目二、题解方法一:深度优先搜索递归方法二:迭代 一、题目 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点…...
ajax、axios、fetch的区别
ajax、axios、fetch 的区别 参考答案: ajax 是指一种创建交互式网页应用的网页开发技术,并且可以做到无需重新加载整个网页的情况下,能够更新部分网页,也叫作局部更新。 使用 ajax 发送请求是依靠于一个对象,叫 XmlHtt…...
Liunx开发工具
Liunx开发工具 1.Linux编辑器-vim使用1.1vim的基本概念1.2vim的基本操作1.3命令模式命令集1.3.1光标定位1.3.2光标移动1.3.3文本复制1.3.4文本操作 1.4插入模式命令集1.5底行模式命令集 2.vim配置3.sudo配置4.Linux编辑器-gcc/g使用4.1背景知识4.2gcc如何操作 5.函数库5.1函数库…...
Docker入门之运行Nginx案例
运行镜像 如果你直接安装会比较慢, 建议参照附录内容配置镜像之后再执行 # 执行命令过程一:下载容器镜像 docker run -d nginx:latest 命令解释 docker run 启动一个容器 -d 把容器镜像中需要执行的命令以daemon(守护进程)的方式运行 nginx…...
【深度学习环境】安装anaconda、tensorflow、pycharm
目录 1.安装anaconda 2.安装tensorflow-gpu 3.安装pycharm 4.VNC操作 5.安装Pytorch PS: linux下常见的操作: 1.Linux下强制关闭程序: 2.导出环境 2.1.pip导出 2.2.conda导出 2.3.其他 3.windows下的环境安装 & pycharm远程配置 4.bash…...
mockery 模拟
composer地址:mockery/mockery - Packagist github地址:地址 文档地址:Mockery — Mockery Docs 1.0-alpha documentation 根据文档介绍,mockery是php mock对象框架。根据js的mock框架的作用,估计mockery也是通过创…...
汽车后视镜反射率检测系统
随着社会的快速发展和物质生活的提供,机动车越来越普及,道路行车安全日益重要。为了保障机动车辆和行人的安全,在行车时不断观察后方和两侧的图像尤为重要。机动车后视镜通过反射镜面可以提供在规定视野内后方和两侧的图像,从而提…...
uni-app引用外部图标库(阿里矢量图)
uni-app引用外部图标库(阿里矢量图) 作为前端程序员,nui-app是必备的,但是有时候内置的图标,组件又不完全满足,这里就可以引进外部图标,这里引用的是阿里矢量图标 第一步,在项目目…...
day49-Todo List(待办事项列表)
50 天学习 50 个项目 - HTMLCSS and JavaScript day49-Todo List(待办事项列表) 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" co…...
寻找丢失数字:数学与位运算的解密之旅
本篇博客会讲解力扣“268. 丢失的数字”的解题思路,这是题目链接。 注意进阶中的描述:你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?这里我会讲解两种思路,它们的时间复杂度是O(N),空间复杂度是O(1)…...
数论分块学习笔记
准备开始复习莫比乌斯反演,杜教筛这一部分,先复习一下数论分块 0.随便说说 数论分块可以计算如下形式的式子 ∑ i 1 n f ( i ) g ( ⌊ n i ⌋ ) \sum_{i1}^{n}f(i)g(\lfloor\frac{n}{i}\rfloor) ∑i1nf(i)g(⌊in⌋)。 利用的原理是 ⌊ n i ⌋ \lf…...
【基础理论】了解点过程
Maximum tsunami wave height generated by the 16 Sept. 2015 Chile earthquake, from the International Tsunami Information Center. Posted by Austin Elliott 一、说明 在这个世界上,会发生许多事件,其趋势可能遵循一种模式。在这篇博客中&#…...
深入理解Spring MVC中的@ResponseBody注解
引言 在现代的Web应用开发中,数据的传递和交互是不可或缺的一部分。Spring MVC作为一个强大的框架,在处理客户端请求和响应时,提供了许多注解来简化开发过程。其中,ResponseBody注解在处理方法的返回值时起到了关键作用࿰…...
大数据学习教程:Linux高级教程(下)
四、大数据集群服务器搭建 1. 新增Linux服务器 1.1、克隆虚拟机 学习环境中,一般使用VMware虚拟机克隆Linux系统,用来进行集群服务器的搭建。 VMware支持两种类型的克隆:完整克隆、链接克隆 完整克隆是和原始虚拟机完全独立的一个复制&…...
Android 11+ 适配实战:破解TextToSpeech ‘speak failed: not bound to TTS engine‘ 的权限与引擎绑定之谜
1. 当语音突然沉默:Android 11的TTS报错之谜 那天我正在调试一个天气预报应用,当代码执行到语音播报"今天晴转多云"时,控制台突然抛出红字警告:speak failed: not bound to TTS engine。这个错误在Android 10及以下版本…...
别再只盯着CAN了!聊聊LIN总线在低成本IoT传感器网络里的那些‘骚操作’
LIN总线在低成本IoT传感器网络中的创新实践 当谈到工业物联网和传感器网络通信协议时,大多数人会立刻想到CAN、Modbus或以太网协议。但有一个被严重低估的选项正在悄然崛起——LIN总线。这个原本为汽车电子设计的轻量级协议,凭借其独特的成本优势和简洁架…...
如何快速上手LeaguePrank:英雄联盟段位修改工具完整实战指南
如何快速上手LeaguePrank:英雄联盟段位修改工具完整实战指南 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank 还在为英雄联盟单调的段位显示感到无聊吗?LeaguePrank是一款开源工具,让你轻松修…...
别再用subprocess了!Mojo原生FFI直连Python C API的5种安全模式,含CPython 3.11+PyPy兼容性矩阵表
第一章:Mojo 与 Python 混合编程案例 生产环境部署Mojo 作为新兴的系统级编程语言,原生兼容 Python 生态,支持在关键性能路径中无缝调用 Mojo 编译模块,同时复用 Python 的成熟工具链与部署基础设施。在生产环境中,典型…...
个人创作者利器:AI净界RMBG-1.4,3秒完成以往30分钟的手动精修
个人创作者利器:AI净界RMBG-1.4,3秒完成以往30分钟的手动精修 1. 为什么你需要AI净界RMBG-1.4? 作为一名内容创作者,你是否经常遇到这些困扰: 拍摄的产品照片背景杂乱,需要花费大量时间手动抠图精心设计…...
IndexTTS2 V23应用案例:打造智能客服语音,让机器说话更有人情味
IndexTTS2 V23应用案例:打造智能客服语音,让机器说话更有人情味 1. 为什么智能客服需要情感语音? 在当今的客户服务场景中,冰冷的机械语音正在被市场淘汰。研究表明,带有适当情感的语音交互能显著提升用户体验&#…...
Nvidia、谷歌、MiniMax、阶跃星辰等60+实战专家齐聚,2026 奇点智能技术大会最新最全日程发布!
责编 | 梦依丹出品 | CSDN(ID:CSDNnews)昨晚,AI 圈彻夜无眠。Claude Code 51 万行源码泄露引发众多开发者连夜 Fork 拆解,OpenAI 创纪录的 1220 亿美元天价融资……这一系列令人眩晕的数字和事件,折射出一个…...
GLM-4.1V-9B-Base开源大模型:面向中文场景优化的轻量级视觉理解基座
GLM-4.1V-9B-Base开源大模型:面向中文场景优化的轻量级视觉理解基座 1. 模型概述 GLM-4.1V-9B-Base是智谱AI开源的一款专注于视觉多模态理解的基础模型,特别针对中文场景进行了优化。这个9B参数的轻量级模型在保持高效推理能力的同时,提供了…...
Intv_AI_MK11 服务端错误处理:全面应对 403 Forbidden 等常见 HTTP 状态码
Intv_AI_MK11 服务端错误处理:全面应对 403 Forbidden 等常见 HTTP 状态码 1. 为什么需要关注API错误处理 在调用Intv_AI_MK11这类AI服务API时,开发者经常会遇到各种HTTP状态码返回。这些状态码就像是服务端给你的"小纸条",告诉你…...
Android开发秘籍:给图片加上独特水印
Android开发秘籍:给图片加上独特水印 为什么要给图片加水印 在当今这个信息飞速传播的时代,图片作为一种直观且富有表现力的信息载体,在我们的生活和工作中无处不在。无论是在社交媒体上分享的精美摄影作品,还是电商平台上展示的…...
