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

工厂方法模式(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&#xff08;待办事项列表&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" co…...

寻找丢失数字:数学与位运算的解密之旅

本篇博客会讲解力扣“268. 丢失的数字”的解题思路&#xff0c;这是题目链接。 注意进阶中的描述&#xff1a;你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题&#xff1f;这里我会讲解两种思路&#xff0c;它们的时间复杂度是O(N)&#xff0c;空间复杂度是O(1)…...

数论分块学习笔记

准备开始复习莫比乌斯反演&#xff0c;杜教筛这一部分&#xff0c;先复习一下数论分块 0.随便说说 数论分块可以计算如下形式的式子 ∑ i 1 n f ( i ) g ( ⌊ n i ⌋ ) \sum_{i1}^{n}f(i)g(\lfloor\frac{n}{i}\rfloor) ∑i1n​f(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 一、说明 在这个世界上&#xff0c;会发生许多事件&#xff0c;其趋势可能遵循一种模式。在这篇博客中&#…...

深入理解Spring MVC中的@ResponseBody注解

引言 在现代的Web应用开发中&#xff0c;数据的传递和交互是不可或缺的一部分。Spring MVC作为一个强大的框架&#xff0c;在处理客户端请求和响应时&#xff0c;提供了许多注解来简化开发过程。其中&#xff0c;ResponseBody注解在处理方法的返回值时起到了关键作用&#xff0…...

大数据学习教程:Linux高级教程(下)

四、大数据集群服务器搭建 1. 新增Linux服务器 1.1、克隆虚拟机 学习环境中&#xff0c;一般使用VMware虚拟机克隆Linux系统&#xff0c;用来进行集群服务器的搭建。 VMware支持两种类型的克隆&#xff1a;完整克隆、链接克隆 完整克隆是和原始虚拟机完全独立的一个复制&…...

1.Oracle建表及使用

1.概述 1. 表&#xff1a;用于 存储数据 -- 是我们最常见的数据库对象 2. 表设计注意事项 (1) 表设计时&#xff0c;尽量遵从 第三范式&#xff08;3NF&#xff09; (2) 名称不能超过 30 个字符 -- 超过会报错 (3) 名称只能以 字母 大头&#xff0c;可由数字、 _、 $…...

《网络是怎样连接的》(二.2)

(6条消息) 《网络是怎样连接的》&#xff08;二.1&#xff09;_qq_38480311的博客-CSDN博客 本文主要取材于 《网络是怎样连接的》 第二章 2.5 2.6章节。 目录 简述&#xff1a; 本文的主要内容是 以太网的收发操作 和 UDP协议的收发操作。 IP与以太网的包收发操作 包是什…...

MySQL加密插件安装

加密插件 查看已经安装的插件&#xff1a;show plugs; 增加加密插件&#xff1a; 登陆MySQL后&#xff0c;通过show variables like ‘validate%’;查看相关验证规则。 ① 在配置文件中新增&#xff0c;[mysqld]标签下 plugin-load-addvalidate_password.so ② 在运行时新增…...

新手入门Jenkins自动化部署入门详细教程

1. 背景 在实际开发中&#xff0c;我们经常要一边开发一边测试&#xff0c;当然这里说的测试并不是程序员对自己代码的单元测试&#xff0c;而是同组程序员将代码提交后&#xff0c;由测试人员测试&#xff1b; 或者前后端分离后&#xff0c;经常会修改接口&#xff0c;然后重新…...

Neural Network学习笔记4

完整的模型训练套路 train.py import torch import torchvision from torch.utils.data import DataLoader # 引入自定义的网络模型 from torch.utils.tensorboard import SummaryWriterfrom model import *# 准备数据集 train_data torchvision.datasets.CIFAR10(root"…...

[转]关于cmake --build .的理解

https://blog.csdn.net/qq_38563206/article/details/126486183 https://blog.csdn.net/HandsomeHong/article/details/120170219 cmake --build . 该命令的含义是&#xff1a;执行当前目录下的构建系统&#xff0c;生成构建目标。 cmake项目构建过程简述: 1. 首先&#xf…...

【Linux下6818开发板(ARM)】硬件空间挂载

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…...

剑指offer 动态规划篇

题目由入门往上递增 入门 斐波那契数列_牛客题霸_牛客网 (nowcoder.com) 动态规划甚至于算法的入门题目 方法一&#xff1a;按照斐波那契的公式fnfn-1fn-2&#xff0c;从1-n求出结果。 class Solution { public:int Fibonacci(int n) {vector<int>f{0,1,1};for(int …...

关于Linux中前端负载均衡之VIP(LVS+Keepalived)自动化部署的一些笔记

写在前面 整理一些 LVS 相关的笔记理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞而凄凉&#xff0c;感到自己的生命被剥夺了。当时我是个年轻人&#xff0c;但我害怕这样生活下去&#xff0c;衰老下去。在我看来…...

C++ 拷贝交换技术示例

拷贝交换技术&#xff08;copy and swap&#xff09;是什么&#xff0c;网上估计能查到很多。但网上有点难找到完整的演示代码&#xff0c;所以这里记录一下。难点在于&#xff1a; 如果要满足 5 的原则&#xff0c;我到底要写那些函数&#xff1f; 默认构造函数、复制构造函数…...