Java设计模式 —— 【创建型模式】工厂模式(简单工厂、工厂方法模式、抽象工厂)详解
文章目录
- 前言
- 一、简单工厂(静态工厂)
- 1、概述
- 2、代码实现
- 3、优缺点
- 二、工厂方法模式
- 1、概述
- 2、代码实现
- 3、优缺点
- 三、抽象工厂模式
- 1、概述
- 2、代码实现
- 3、优缺点
- 四、总结
前言
先看个案例:【手机和手机店】在没有工厂的时候,手机店需要手机就需要自己创建,还得根据用户的选择进行创建不同的手机,如下图:
这样手机店直接与手机对象接触,就会对该对象耦合严重,假如我们添加新的手机品牌,还得修改手机店的create方法,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,将对象的创建封装在工厂内,实现使用者和对象解耦;所以说,工厂模式最大的优点就是:解耦。
工厂模式的主要目的是将对象的创建过程封装在工厂类中,客户端代码只需要关心从工厂获取对象的过程,而不需要了解对象的创建细节。这样可以降低代码的耦合度,提高代码的可维护性和可扩展性
一、简单工厂(静态工厂)
1、概述
简单工厂不是一种设计模式,反而比较像是一种编程习惯。把对象的创建和业务逻辑层分开,实现使用方(手机店)与对象(手机)的解耦。但工厂和产品之间还是存在耦合关系。
主要包含以下角色:
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品: 实现或者继承抽象产品的子类
- 具体工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。
2、代码实现
抽象手机类【抽象产品】:
public abstract class Phone {public abstract String getName();
}
手机产品【具体产品】:
public class HuaWei extends Phone {@Overridepublic String getName() {return "华为手机";}
}public class XiaoMi extends Phone {@Overridepublic String getName() {return "小米手机";}
}
手机工厂【具体工厂】:
public class Factory {public static Phone createPhone(String name) {Phone phone = null;if("小米".equals(name)) {phone = new XiaoMi();} else if("华为".equals(name)) {phone = new HuaWei();}return phone;}
}
手机店【使用者】:
public class Sotre {public static Phone orderPhone(String name) {return Factory.createPhone(name);}
}
测试:
public class Test {public static void main(String[] args) {Phone xiaomi = Sotre.orderPhone("小米");System.out.println(xiaomi.getName());Phone huawei = Sotre.orderPhone("华为");System.out.println(huawei.getName());}
}
3、优缺点
优点:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
二、工厂方法模式
1、概述
在在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体的工作交给子类去做。 定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。很好的解决了简单工厂的问题,遵循开闭原则。
工厂方法模式的主要角色:
- 抽象工厂: 提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
2、代码实现
抽象手机类【抽象产品】:
public abstract class Phone {public abstract String getName();
}
手机产品【具体产品】:
//小米手机
public class XiaoMi extends Phone {@Overridepublic String getName() {return "小米手机";}
}//华为手机
public class HuaWei extends Phone {@Overridepublic String getName() {return "华为手机";}
}
抽象工厂:
class interface PhoneFactory {Phone createPhone();
}
具体工厂:
//小米工厂
public class XiaoMiFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new XiaoMi();}
}//华为工厂
public class HuaWeiFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new HuaWei();}
}
手机店【使用者】:
public class Store {public Phone orderPhone(PhoneFactory factory) {return factory.createPhone();}
}
测试:
public class Test {public static void main(String[] args) {Store store = new Store();Phone huaWei = store.orderPhone(new HuaWeiFactory());Phone xiaomi = store.orderPhone(new XiaoMiFactory());System.out.println(xiaomi.getName());System.out.println(huaWei.getName());}
}
3、优缺点
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
三、抽象工厂模式
1、概述
抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产同一个等级的产品(小米手机,华为手机),而抽象工厂模式可生产多个等级的产品(小米家族,华为家族)。
抽象工厂模式的主要角色如下:
- 抽象工厂: 提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品(小米工厂和华为工厂的所有功能的抽象【创建手机,创建路由器】)。
- 具体工厂: 主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建(小米工厂造小米家族产品,华为工厂造华为家族产品)。
- 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品(小米和华为所拥有的同一系列产品的抽象【手机产品,路由器产品】)。
- 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
2、代码实现
抽象工厂:
public interface Factory {// 生产手机Phone createPhone();// 生产路由器Router createRouter();
}
具体工厂:
//小米工厂
public class XiaoMiFactory implements Factory {@Overridepublic Phone createPhone() {return new XiaoMiPhone();}@Overridepublic Router createRouter() {return new XiaoMiRouter();}
}//华为工厂
public class HuaWeiFactory implements Factory {@Overridepublic Phone createPhone() {return new HuaWeiPhone();}@Overridepublic Router createRouter() {return new HuaWeiRouter();}
}
抽象产品:
//手机产品
public abstract class Phone {public abstract String getName();
}//路由器类
public abstract class Router {public abstract String getName();
}
具体产品:
public class XiaoMiPhone extends Phone{@Overridepublic String getName() {return "小米手机";}
}public class HuaWeiPhone extends Phone {@Overridepublic String getName() {return "华为手机";}
}
public class XiaoMiRouter extends Router {@Overridepublic String getName() {return "小米路由器";}
}public class HuaWeiRouter extends Router {@Overridepublic String getName() {return "华为路由器";}
}
手机店:
public class Store {private Factory factory;public void setFactory(Factory factory) {this.factory = factory;}public Phone orderPhone(){return factory.createPhone();}public Router orderRouter(){return factory.createRouter();}
}
测试:
public class Test {public static void main(String[] args) {Store store = new Store();store.setFactory(new XiaoMiFactory());Phone xiaomiPhone = store.orderPhone();Router xiaomiRouter = store.orderRouter();System.out.println(xiaomiPhone.getName());System.out.println(xiaomiRouter.getName());System.out.println("===========");store.setFactory(new HuaWeiFactory());Phone huaweiPhone = store.orderPhone();Router huaweiRouter = store.orderRouter();System.out.println(huaweiPhone.getName());System.out.println(huaweiRouter.getName());}
}
如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。
3、优缺点
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
四、总结
- 以上述案例为例,没有工厂就是手机店直接造手机,使用者和对象高度耦合,新增品类时违背开闭原则,一个手机店造不同手机违背单一职责原则;
- 由此引出简单工厂,手机店只需要和工厂打交道,售卖手机,不负责造手机的过程,实现手机店和对象的解耦,但是工厂和对象还是存在上述问题;
- 由此工厂在向上抽象出“工厂规范”,形成工厂方法模式,不同的工厂负责不同的职责,添加新的品类时增加对应工厂和产品即可;
- 在往下走,工厂做大做强以后,不只是可以生产手机,还添加了新的产品路由器,形成抽象工厂模式。
- 工厂方法模式是针对单一的品类进行的实现,二抽象工厂是针对多个品类(产品族)的实现。
相关文章:

Java设计模式 —— 【创建型模式】工厂模式(简单工厂、工厂方法模式、抽象工厂)详解
文章目录 前言一、简单工厂(静态工厂)1、概述2、代码实现3、优缺点 二、工厂方法模式1、概述2、代码实现3、优缺点 三、抽象工厂模式1、概述2、代码实现3、优缺点 四、总结 前言 先看个案例:【手机和手机店】在没有工厂的时候,手…...

KST-3D01型胎儿超声仿真体模、吸声材料以及超声骨密度仪用定量试件介绍
一、KST-3D01型胎儿超声仿真体模 KST—3D01型胎儿超声体模,采用仿羊水环境中内置胎龄为7个月大仿胎儿设计。用于超声影像系统3D扫描演示装置表面轮廓呈现和3D重建。仿羊水超声影像呈暗回声(无回波)特性,仿胎儿超声影像呈对比明显…...

网络原理->DNS协议和NAT协议解
前言 大家好我是小帅,今天我们来了解应用层的DNS协议和NAT技术 个人主页:再无B~U~G 文章目录 1.重要应⽤层协议DNS(Domain Name System)1.1 DNS背景 2. NAT技术3. 总结 1.重要应⽤层协议DNS(Domain Name System) DNS是⼀整套从域…...

基于yolov8、yolov5的100种中药材检测识别系统(含UI界面、训练好的模型、Python代码、数据集)
项目介绍 项目中所用到的算法模型和数据集等信息如下: 算法模型: yolov8、yolov8 SE注意力机制 或 yolov5、yolov5 SE注意力机制 , 直接提供最少两个训练好的模型。模型十分重要,因为有些同学的电脑没有 GPU࿰…...
RuoYi排序
RuoYi框架提供了多种实现排序的方法,以满足不同场景下的需求。这里简要介绍几种常见的排序实现方式: 1. 后端排序 1.1 使用startPagePlus方法 RuoYi框架中,可以通过对BaseController进行扩展来实现更灵活的分页与排序功能。例如࿰…...

Python+Pytest+Yaml+Allure数据参数化(DDT)数据驱动(一)
我们在做数据之前要知道几个问题 1、在代码层面怎么来数据驱动 2、yaml文件是什么 3、怎么用yaml文件实现对应的数据驱动 我们用的是pytest框架所以相对来说是简单的,我们通过pytest框架来实现,而框架中要数据驱动用到我们装饰器就好啦pytest.mark.p…...

BASLER工业相机维修不能触发拍照如何处理解决这个问题
BASLER工业相机维修不能触发拍照如何处理解决这个问题?最近遇到挺多工业相机维修咨询这个不能触发拍照的案例,所以今天优米佳维修的技术就抽空整理了这篇关于BASLER相机不能触发拍照的处理方法分享给大家。 当碰到巴斯勒工业相机不能触发拍照的问题&…...

Could not locate device support files.
报错信息:Failure Reason: The device may be running a version of iOS (13.6.1 17G80) that is not supported by this version of Xcode.[missing string: 869a8e318f07f3e2f42e11d435502286094f76de] 问题:xcode15升级到xcode16之后,13.…...
linux系统中常用文件日常使用命令记录
我们办公机是Ubuntu系统; 记录下工作中经常使用的几个文件或命令或一些零碎的知识点: (该文档会持续更新) 查看系统信息: uname -a cat /etc/product-info cat /etc/os-version 存放系统启停脚本 /etc/init.d/ 存放源…...

【C++打怪之路Lv16】-- map set
🌈 个人主页:白子寰 🔥 分类专栏:重生之我在学Linux,C打怪之路,python从入门到精通,数据结构,C语言,C语言题集👈 希望得到您的订阅和支持~ 💡 坚持…...
TPU-MLIR 项目源码结构分析
TPU-MLIR 项目源码结构分析 本文用作学习记录和交流分享,主要内容为 TPU-MLIR 的源码框架分析和构建流程分析。源码地址:https://github.com/sophgo/tpu-mlir 文件结构 从最外层开始分析 envsetup.sh 该脚本用于配置和初始化开发环境,其中…...

IDEA Maven 打包找不到程序包错误或找不到符号,报错“程序包不存在“
参考文章:https://blog.csdn.net/yueeryuanyi/article/details/14211090 问题:IDEA Maven 打包找不到程序包错误或找不到符号,报错“程序包不存在“编译都没问题 解决思路 – >【清除缓存】 1. 强制刷新Maven缓存 选择 Maven 标签,Exe…...
Sourcetree:一款强大的Git客户端
Sourcetree:一款强大的Git客户端 Sourcetree是一款由Atlassian开发的免费Git客户端,它提供了一个直观的图形界面,让用户能够轻松地管理他们的版本控制系统。无论是初学者还是有经验的开发者,Sourcetree都能提供方便快捷的Git操作…...
Linux环境变量与本地变量
文章目录 Linux环境变量与本地变量什么是环境变量查看环境变量设置环境变量本地变量命令行参数 Linux环境变量与本地变量 什么是环境变量 操作系统或运行时环境中存储的一些变量,用来存储与进程或系统相关的配置信息。这些变量在进程启动时由操作系统或Shell读取&…...

ChatGPT的应用场景:开启无限可能的大门
ChatGPT的应用场景:开启无限可能的大门 随着人工智能技术的快速发展,自然语言处理领域迎来了前所未有的突破。其中,ChatGPT作为一款基于Transformer架构的语言模型,凭借其强大的语言理解和生成能力,在多个行业和场景中展现出了广泛的应用潜力。以下是ChatGPT八个最具代表…...

QT按下两次按钮,保存这期间内变换的QtextEdit控件内的数据
这个功能在项目中很常见,对界面里某个控件的数据进行记录,我这个是每秒记录5次,实际就是每200ms触发一次定时器,来满足需求。 .h文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QtSerialPort> …...
daos源码编译
1. 前言 本文详细介绍如何在almalinux8.9上编译daos.2.0.0源码。系统环境如下: daos: 2.0.0 linux os: almalinux 8.9 linux kernel: 4.18.0-513.5.1.el8_9.x86_64之所以选择2.0.0版本,是因为daos从2.0.0开始是一个全新的架构设计&a…...

HTML飞舞的爱心
目录 系列文章 写在前面 完整代码 代码分析 写在后面 系列文章 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心(简易版)7HTML粒子爱心8HTML蓝色…...

C++中智能指针的使用及其原理 -- RAII,内存泄漏,shared_ptr,unique_ptr,weak_ptr
目录 1.智能指针的使用场景分析 2.RAII和智能指针的设计思路 3.C标准库智能指针的使用 4.智能指针的原理以及模拟实现 5.shared_ptr循环引用问题和weak_ptr 5.1shared_ptr循环引用问题 5.2weak_ptr的原理和部分接口 5.3weak_ptr的简单模拟实现 6. shared_ptr的线程安…...

Linux服务器安装mongodb
因为项目需要做评论功能,领导要求使用mongodb,所以趁机多学习一下。 在服务器我们使用docker安装mongodb 1、拉取mongodb镜像 docker pull mongo (默认拉取最新的镜像) 如果你想指定版本可以这样 docker pull mongo:4.4&#…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...

基于Python的气象数据分析及可视化研究
目录 一.🦁前言二.🦁开源代码与组件使用情况说明三.🦁核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.🦁演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...
【向量库】Weaviate 搜索与索引技术:从基础概念到性能优化
文章目录 零、概述一、搜索技术分类1. 向量搜索:捕捉语义的智能检索2. 关键字搜索:精确匹配的传统方案3. 混合搜索:语义与精确的双重保障 二、向量检索技术分类1. HNSW索引:大规模数据的高效引擎2. Flat索引:小规模数据…...

循环神经网络(RNN):从理论到翻译
循环神经网络(RNN)是一种专为处理序列数据设计的神经网络,如时间序列、自然语言或语音。与传统的全连接神经网络不同,RNN具有"记忆"功能,通过循环传递信息,使其特别适合需要考虑上下文或顺序的任…...