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

【Java开发】设计模式 02:工厂模式

1 工厂模式介绍

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1.1 场景

  • 目的:使用工厂代替new操作,使代码结构清晰,有效地封装变化;

  • 适用:在任何需要生成复杂对象的地方,都可以使用工厂方法模式

  1. 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

  1. 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

  1. 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

  • 优点

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。

  1. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

  1. 屏蔽产品的具体实现,调用者只关心产品的接口。

  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

根据迪米特法则,应该尽可能地少与其他类进行交互,所以可以将那些需要频繁出现的对象创建,封装到一个工厂类中。当需要对象时,直接调用工厂类中的工厂方法来生成对象,这样,就算类出现了变动,只需要修改工厂中的代码即可,而不是大面积地进行修改。同时,可能某些对象的创建并不只是一个 new 就可以搞定,可能还需要更多的步骤来准备构造方法需要的参数。

1.2 简单工厂模式实现

简单工厂其实不是一个标准的的设计模式。GOF 23 种设计模式中只有「工厂方法模式」与「抽象工厂模式」。简单工厂模式可以看为工厂方法模式的一种特例,为了统一整理学习,就都归为工厂模式。

下面以水果工厂生产水果为例介绍普通工厂模式:

📌 1.定义水果类

//水果类
public class Fruit {private final String name;public Fruit(String name){this.name = name;}
}

📌 2.定义苹果类和橙子类

//苹果类
public class Apple extends Fruit{public Apple() {super("苹果");}
}
//橙子类
public class Orange extends Fruit{public Orange() {super("橙子");}
}

📌 3.定义水果工厂

//水果工厂
public class FruitFactory{/*** 这里就直接使用静态方法根据指定类型进行创建* @param type 水果类型* @return 对应的水果对象*/public static Fruit getFruit(String type){switch (type){case "苹果":return new Apple();case "橙子":return new Orange();default:return null;}}
}

📌 4.调用

// 直接问工厂要,而不是自己去创建
Apple apple = (Apple) FruitFactory.getFruit("苹果");
Orange orange = (Orange) FruitFactory.getFruit("橙子");

📢 总结

工厂类是整个简单工厂模式的关键。包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。

不过这样还是有一些问题,比如开闭原则,一个软件实体,比如类、模块和函数应该对扩展开放,对修改关闭。此时如果需要新增一种水果,比如桃子,那么就得去修改工厂提供的工厂方法了,这样是不太符合开闭原则的。因为工厂实际上是针对于调用方提供的,所以应该尽可能对修改关闭。

2 工厂方法模式

我们就利用对扩展开放,对修改关闭的性质,将简单工厂模式改进为工厂方法模式,既然不让改,那么就看看如何去使用扩展的形式。

这里还是以水果工厂生产水果介绍工厂方法模式:

📌 1.定义水果工厂

import com.yinyu.study.factory.simple.Fruit;/*** 水果工厂* <p>将水果工厂抽象为抽象类,添加泛型 T 由子类指定水果类型*/
public abstract class FruitFactory<T extends Fruit> {/*** 不同的水果工厂,通过此方法生产不同的水果* @return 水果对象*/public abstract T getFruit();
}

📌 2.定义苹果工厂和橙子工厂

import com.yinyu.study.factory.simple.Apple;public class AppleFactory extends FruitFactory<Apple>{/*** 获取苹果对象* @return 苹果对象*/@Overridepublic Apple getFruit() {return new Apple();}
}
import com.yinyu.study.factory.simple.Orange;public class OrangeFactory extends FruitFactory<Orange>{/*** 获取橙子对象* @return 橙子对象*/@Overridepublic Orange getFruit() {return new Orange();}
}

这样,就可以使用不同类型的工厂来生产不同类型的水果了,如果新增了水果类型,直接创建一个新的工厂类就行,不需要修改之前已经编写好的内容。

📌 3.调用

// 使用对应的工厂生产对应的对象
Apple apple = new AppleFactory().getFruit();
Orange orange = new OrangeFactory().getFruit();

这样实现了工厂方法模式,通过工厂来屏蔽对象的创建细节,使用者只需要关心如何去使用对象即可。

📢 总结

由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

3 抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类,抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或 Toolkit)模式。

这里以云南工厂生产水果介绍抽象工厂模式:

📌 1.定义香蕉和芒果接口

public interface Banana {void bananaInfo();
}
public interface Mango {void mangoInfo();
}

📌 2.定义云南香蕉和云南芒果工厂

public class YunnanBanana implements Banana{@Overridepublic void bananaInfo() {System.out.println("云南香蕉");}
}
public class YunnanMango implements Mango{@Overridepublic void mangoInfo() {System.out.println("云南芒果");}
}

📌 3.定义工厂接口生产香蕉和芒果

public interface Factory {Banana proBanana();Mango proMango();
}

📌 4.定义云南工厂类实现工厂接口

public class YunnanFactory implements Factory{@Overridepublic Banana proBanana() {return new YunnanBanana();}@Overridepublic Mango proMango() {return new YunnanMango();}
}

📌 5.调用

Factory factory = new YunnanFactory();YunnanBanana banana = (YunnanBanana) factory.proBanana();
YunnanMango mango = (YunnanMango) factory.proMango();banana.bananaInfo();
mango.mangoInfo();

📢 总结

云南工厂类似一个产品族,它可以生产云南香蕉和云南芒果,那么也可以很方便地创建一个广西工厂,用来生产广西香蕉和广西芒果;不过倘若各工厂要生产一件新的水果,那么工厂接口和各具体工厂都将进行修改,如此会造成较大麻烦。

相关文章:

【Java开发】设计模式 02:工厂模式

1 工厂模式介绍工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使…...

合并两个链表(自定义位置合并与有序合并)LeetCode--OJ题详解

图片: csdn 自定义位置合并 问题&#xff1a; 给两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中 下标从 a 到 b 的全部节点都删除&#xff0c;并将list2 接在被删除节点 的位置。 比如&#xff1a; 输入&#xff1a;list1 [1…...

Java编程问题总结

Java编程问题总结 整理自 https://github.com/giantray/stackoverflow-java-top-qa 基础语法 将InputStream转换为String apache commons-io String content IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8); //String value FileUtils.readFileT…...

binutils工具集——objcopy的用法

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 一、工具简介 objcopy主要用来转换目标文件的格式。 在实际开发中&#xff0c;我们会用该工具进行格式转换与内容删除。 &#xff08;1&#xff09;在链接完成后&#xff0c;将elf格式的.out文件转化为bi…...

Windows使用Stable Diffusion时遇到的各种问题和知识点整理(更新中...)

Stable Diffusion安装完成后&#xff0c;在使用过程中会出现卡死、文件不存在等问题&#xff0c;在本文中将把遇到的问题陆续记录下来&#xff0c;有兴趣的朋友可以参考。 如果要了解如何安装sd&#xff0c;则参考本文《Windows安装Stable Diffusion WebUI及问题解决记录》。如…...

MySQL workbench基本查询语句

1.查询所有字段所有记录 SELECT * FROM world.city; select 表示查询&#xff1b;“*” 称为通配符&#xff0c;也称为“标配符”。表示将表中所有的字段都查询出来&#xff1b;from 表示从哪里查询&#xff1b;world.city 表示名为world的数据库中的city表&#xff1b; 上面…...

软件测试详解

文章目录一、软件危机&#xff08;一&#xff09;概念&#xff08;二&#xff09;产生软件危机的原因&#xff08;三&#xff09;消除软件危机的途径二、软件过程模型&#xff08;一&#xff09;软件生命周期概念&#xff08;二&#xff09;软件开发模型1. 瀑布模型2. 螺旋模型…...

YOLOS学习记录

在前面&#xff0c;博主已经完成了YOLOS项目的部署与调试任务&#xff0c;并在博主自己构造的数据集上进行了实验&#xff0c;实验结果表明效果并不显著&#xff0c;其实这一点并不意外&#xff0c;反而是在情理之中。众所周知&#xff0c;Transformer一直以来作为NLP领域的带头…...

数组边遍历(for循环)边删除为什么删不干净 及三种实现删除的方法

文章目录1、为什么删不干净倒序删迭代器lambda表达式删除为什么说数组边for循环遍历边删除会出现删不干净的情况1、为什么删不干净 先写一个例子&#xff1a;可以先猜一下控制台会打印出什么内容&#xff1f; public class removeIterator {public static void main(String[]…...

环境配置之Keepass

前言很久以前&#xff0c;就有了想要一个自己密码管理器的念头。毕竟&#xff0c;即使浏览器能记住各个网站的账号密码&#xff0c;但是在登录单独客户端的时候&#xff0c;仍然要翻找密码。为了省事&#xff0c;也曾经是一个密码走天下。然后被劫持了QQ给同学发黄色小网站&…...

Java 电话号码的组合

电话号码的字母组合中等给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。示例 1&#xff1a;输入&#xff1a;digits "23…...

MATLAB——将直接型转化为并联型和级联型

题目1(IIR)&#xff1a; 已知一个系统的传递函数为&#xff1a; H&#xff08;z&#xff09;8−4z−111z−2−2z−31−1.25z−10.75z−2−0.125z−3H&#xff08;z&#xff09;\frac{8-4z^{-1}11z^{-2}-2z^{-3}}{1-1.25z^{-1}0.75z^{-2}-0.125z^{-3}}H&#xff08;z&#xff09…...

.NET Framework .NET Core与 .NET 的区别

我们在创建C#程序时,经常会看到目标框架以下的选项,那么究竟有什么区别? 首先 .NET是一种用于构建多种应用的免费开源开发平台,可以使用多种语言,编辑器和库开发Web应用、Web API和微服务、云中的无服务器函数、云原生应用、移动应用、桌面应用、Windows WPF、Windows窗体…...

carla与ros2的自动驾驶算法-planning与control算法开发与仿真

欢迎仪式 carla与ros2的自动驾驶算法-planning与control算法开发与仿真欢迎大家来到自动驾驶Player(L5Player)的自动驾驶算法与仿真空间&#xff0c;在这个空间我们将一起完成这些事情&#xff1a; 控制算法构建基础模块并仿真调试&#xff1a;PID、LQR、Stanley 、MPC、滑膜控…...

corn表达式

简单理解corn表达式&#xff1a;在使用定时调度任务的时候&#xff0c;我们最常用的&#xff0c;就是cron表达式了。通过cron表达式来指定任务在某个时间点或者周期性的执行。cron表达式配置起来简洁方便&#xff0c;无论是Spring的Scheduled还是用Quartz框架&#xff0c;都支持…...

推荐系统中对抗性机器学习-文献综述与未来发展整理分享

对抗学习是一种机器学习技术&#xff0c;旨在通过提供欺骗性输入来欺骗模型。最常见的原因是导致机器学习模型出现故障。大多数机器学习技术旨在处理特定的问题集&#xff0c;其中从相同的统计分布&#xff08;IID&#xff09;生成训练和测试数据。当这些模型应用于现实世界时&…...

Proteus8.15安装教程

1、解压Proteus8.15 安装包&#xff0c;然后双击进去&#xff0c;找到setup文件&#xff0c;右键&#xff0c;以管理员身份运行。 2、需要安装一些插件&#xff0c;点击“next”。把插件安装完成。 点击“finfish” 点击“install” 点击“Cancel” 3、如果没有上面步骤&…...

Shell 基本运算符

Shell 和其他编程语言一样&#xff0c;支持多种运算符&#xff0c;包括&#xff1a; 算数运算符关系运算符布尔运算符字符串运算符文件测试运算符 原生bash不支持简单的数学运算&#xff0c;但是可以通过其他命令来实现&#xff0c;例如 awk 和 expr&#xff0c;expr 最常用。…...

Linux基础命令-sed流编辑器

Linux三剑客-grep命令 Sed 一. 命令介绍 先到帮助文档中查看命令的描述信息 NAME sed - stream editor for filtering and transforming text sed命令是操作、过滤和转换文本内容的强大工具&#xff0c;常用功能包括结合正则表达式对文件实现快速增删改查&#xff0c;其中查询…...

C语言笔试题(1)

#include <stdio.h> #include <stdlib.h> #include <string.h> void getmemory(char *p) { p(char *) malloc(100); strcpy(p,“hello world”); } int main(void) { char *strNULL; getmemory(str); printf(“%s/n”,str); free(str); return 0; } 上述程序…...

构建大规模数据导入系统:技术选型与工程实践

在现代数据密集型应用中&#xff0c;将海量数据高效、可靠地导入目标存储系统是一项基础但极具挑战的任务。表面上看&#xff0c;“写入数据库”只是一个简单的操作&#xff1b;然而&#xff0c;当数据规模达到TB级、业务逻辑涉及合并去重、系统架构包含多个存储引擎时&#xf…...

小白也能搞定!用Docker和Halo 2.10搭建个人博客,再也不用担心公网访问问题

零基础玩转DockerHalo 2.10&#xff1a;打造高颜值个人博客全攻略 在数字内容创作爆发的时代&#xff0c;拥有一个专属博客空间已成为个人品牌建设的标配。但传统建站方案往往面临技术门槛高、维护成本大等痛点。本文将带你用Docker容器技术和Halo 2.10开源系统&#xff0c;30…...

MedGemma Medical Vision LabGPU优化:FP16量化+KV Cache压缩使A10显存占用降低42%

MedGemma Medical Vision Lab GPU优化&#xff1a;FP16量化KV Cache压缩使A10显存占用降低42% 1. 项目背景与挑战 MedGemma Medical Vision Lab 是一个基于 Google MedGemma-1.5-4B 多模态大模型构建的医学影像智能分析 Web 系统。这个系统通过 Web 界面实现医学影像与自然语…...

基于Python的流浪动物救助平台毕业设计

博主介绍&#xff1a;✌ 专注于Java,python,✌关注✌私信我✌具体的问题&#xff0c;我会尽力帮助你。一、研究目的本研究旨在构建一个基于Python的流浪动物救助平台&#xff0c;以实现流浪动物的有效救助与管理工作。具体研究目的如下&#xff1a; 首先&#xff0c;通过构建流…...

Qwen2.5-VL-7B-Instruct应用场景:跨境电商商品图自动打标+多语种描述生成

Qwen2.5-VL-7B-Instruct应用场景&#xff1a;跨境电商商品图自动打标多语种描述生成 1. 跨境电商的痛点与解决方案 跨境电商卖家每天面临两个核心挑战&#xff1a;商品图片标注和多语言描述撰写。传统方式需要人工逐张图片添加标签&#xff0c;再用翻译工具转换语言&#xff…...

动态规划详解:从入门到精通,这四个案例让你彻底掌握DP思想

面试必考、算法进阶的核心&#xff0c;一篇文章帮你打通任督二脉在算法学习的过程中&#xff0c;动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;绝对是让很多人头疼的一个难点。很多初学者看到DP问题就发怵&#xff0c;其实只要掌握了核心思想&#x…...

别再让AI瞎忙活了!用Claude Code的SubAgent打造你的专属开发团队(附React项目实战)

别再让AI瞎忙活了&#xff01;用Claude Code的SubAgent打造你的专属开发团队&#xff08;附React项目实战&#xff09; 在软件开发的世界里&#xff0c;我们常常面临一个困境&#xff1a;要么雇佣一个庞大的团队&#xff0c;每个成员各司其职但成本高昂&#xff1b;要么依赖全能…...

SDMatte多平台适配实践:Chrome/Firefox/Safari在Web抠图交互中的兼容性与性能表现

SDMatte多平台适配实践&#xff1a;Chrome/Firefox/Safari在Web抠图交互中的兼容性与性能表现 1. 引言 SDMatte是一款面向高质量图像抠图场景的AI模型&#xff0c;特别擅长处理主体分离、透明物体提取、边缘精修等任务。对于玻璃、薄纱、羽毛、叶片等边缘细节复杂或半透明目标…...

Biolaminin 层粘连蛋白(LN521)在干细胞培养中的作用与应用解析【曼博生物官方代理BioLamina】

摘要&#xff1a;人类重组层粘连蛋白&#xff08;Laminin&#xff09;&#xff0c;尤其是LN521亚型&#xff0c;在多能干细胞培养中具有重要作用。本文从细胞微环境、培养体系及应用场景角度&#xff0c;对其在干细胞研究与转化中的价值进行系统梳理。 关键词&#xff1a;LN521…...

如何打造个人游戏云:5步掌握Sunshine跨平台串流技术

如何打造个人游戏云&#xff1a;5步掌握Sunshine跨平台串流技术 【免费下载链接】Sunshine Sunshine: Sunshine是一个自托管的游戏流媒体服务器&#xff0c;支持通过Moonlight在各种设备上进行低延迟的游戏串流。 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine…...