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&#…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...