3、设计模式之工厂模式2(Factory)
一、什么是工厂模式
工厂模式属于创建型设计模式,它用于解耦对象的创建和使用。通常情况下,我们创建对象时需要使用new操作符,但是使用new操作符创建对象会使代码具有耦合性。工厂模式通过提供一个公共的接口,使得我们可以在不暴露对象创建逻辑的情况下创建对象。
二、工厂分类
工厂模式分为三种类型:简单工厂、方法工厂和抽象工厂,其本质就是对获取对象过程的抽象。
三、应用场景
3.1 生活场景
你需要一辆汽车,可以直接从工厂里提货,而不用关心它具体是怎么实现的
Hibernate换数据库只需要换方言和驱动就可以
3.2 java场景
BeanFactory:它是Spring
IoC容器的核心接口,通过读取配置文件或注解来创建Bean实例,并将它们注入到其他对象中。BeanFactory使用了工厂模式来隐藏具体的对象实例化过程,客户端只需要通过接口获取Bean对象,而不需要关心具体的实例化细节。
FactoryBean:是一种更高级别的工厂模式实现,用于创建特定类型的Bean对象。与普通的BeanFactory不同,FactoryBean的getObject()方法可以返回任意类型的对象实例,并且可以通过配置方式创建和管理实例。
Executors:提供了一系列的工厂方法来创建线程池(ThreadPoolExecutor)及其相关组件。
Charset:提供了一系列的静态工厂方法,如forName()、availableCharsets()等,用于创建Charset实例。

4.1 传统模式
在介绍工厂模式之前先来看看传统模式,以卖包子为例,如下:
//简单的制作流程
public BaoZi createBaoZi() {BaoZi baozi = new BaoZiImpl();//准备材料baozi.prepare();//制作包子baozi.make();//蒸包子baozi.braise();return baozi;
}
包子肯定有很多种类吧,那我们可以直接在上述代码中添加根据包子的种类生成不同类型的对象
/**
* 包子肯定有不同的馅:酸菜、豆沙、猪肉,那么他的材料、售价等方式也不同
* 我们可以直接在上述代码中,添加根据包子的不同种类生成不同的对象。
*/
public BaoZi createBaoZi(String type) {BaoZi baoZi = null;switch (type){case "suancai":baoZi=new SuanCaiBaoZi();break;case "dousha":baoZi=new DouShaBaoZi();break;case "pork":baoZi=new PorkBaoZi();break;default:throw new IllegalArgumentException("Invalid BaoZi Type");}//准备材料baoZi.prepare();//制作包子baoZi.make();//蒸包子baoZi.braise();return baoZi;
}
Test:
//1.传统模式@Testvoid traditonal(){SaleBaoZi saleBaoZi=new SaleBaoZi();//以猪肉包为例saleBaoZi.createBaoZi("pork");}
4.2 简单工厂模式
简单工程根据客户端的需求创建具体的实例,这种模式对调用者隐藏了实例创建的过程,也使得创建过程更加容易维护。
还是以卖包子为例,简单工厂模式实现如下:
/*** 2.简单工厂方法:希望能够创建一个对象,但创建过程比较复杂,希望对外隐藏这些细节*/
public class SimpleFactory {public static BaoZi createBaoZi(String type){BaoZi baoZi=null;switch (type){case "suancai":baoZi=new SuanCaiBaoZi("酸菜包");break;case "dousha":baoZi=new DouShaBaoZi("豆沙包");break;case "pork":baoZi=new PorkBaoZi("猪肉包");case "beef"://老板拓展业务了,新加了一个牛肉包类型的包子,那对于简单工厂模式而言,//于是就得修改源代码,那么就违反了ocp原则,假如新增100个?baoZi=new BeefBaoZi("牛肉包");break;default:throw new IllegalArgumentException("Invalid BaoZi Type");}return baoZi;}
}
Test:
//2.简单工厂模式@Testvoid simpleFactory(){//以猪肉包为例BaoZi pork = SimpleFactory.createBaoZi("pork");pork.prepare();pork.make();pork.braise();}
相比传统模式,从类图上就可以看出来,在sale和baozi中间又加了一层。
通过封装SimpleFactory这个类,我们将sale和baozi进行了解耦合。
4.3 方法工厂模式
简单工厂模式下,如果老板拓展业务了,加了一个牛肉种类的包子,就得在源码基础上修改,那么这就违背了开闭原则(ocp),即对扩展开放,对修改关闭。于是,为了解决这个问题,就又了工厂方法模式。
工厂方法模式是一种更加抽象的工厂模式,它将工厂的职责抽象为接口,由具体的工厂实现创建具体的对象。工厂方法模式弱化了工厂的实现,使得每个工厂只负责一个产品的创建。
抽象工厂MeAbStractFactory:
public interface MeAbstractFactory {BaoZi createBaoZi();
}
DouShaFactory:
//豆沙包
public class DouShaFactory implements MeAbstractFactory {@Overridepublic BaoZi createBaoZi() {return new DouShaBaoZi("豆沙包");}
}
PorkFactory:
//猪肉包
public class PorkFactory implements MeAbstractFactory {@Overridepublic BaoZi createBaoZi() {return new PorkBaoZi("猪肉包");}
}
BeefFactory:
//牛肉包
public class BeefFactory implements MeAbstractFactory {@Overridepublic BaoZi createBaoZi() {return new BeefBaoZi("牛肉包");}
Test:
//3.方法工厂模式@Testvoid methodFactory(){MeAbstractFactory factory=new PorkFactory();BaoZi pork = factory.createBaoZi();pork.prepare();pork.make();pork.braise();}
之前的SimpleFactory在createBaoZi中直接就new出来了,但在方法工厂中,我们将createBaoZi这个动作推迟到了MeAbStactFactory的子类(XXFactory)中才完成。
好处就是,比如后期要卖个羊肉包,我们直接编写个羊肉包类,然后实现MeAbstractFactory类就,实现它自己的功能,这样完全不用修改原来的代码了,也就解决了违反OCP原则的问题。
4.4 抽象工厂模式
抽象工厂模式是基于工厂方法模式的基础上进行的。在这种模式中,每一个工厂不再只负责一个产品的创建,而是负责一组产品的创建。抽象工厂模式将每个产品组都提取为一个接口,每个工厂都负责一个产品组。
假如老板的生意做大了,在北京开了个分店,并且不止卖包子,还卖蛋糕,那么该怎么拓展呢,很简单,只需要在抽象工厂类中新增创建蛋糕的抽象方法就行,如下:
AbstractFactory:public interface AbstractFactory {//制作包子BaoZi createBaoZi(String type);//制作蛋糕Cake createCake(String type);
}
BJFactory:
//北京分店
public class BJFactory implements AbstractFactory{@Overridepublic BaoZi createBaoZi(String type) {BaoZi baoZi=null;switch (type){case "beef":baoZi=new BJBeefBao("北京牛肉包");break;case "pork":baoZi=new BJPorkBao("北京猪肉包");default:break;}return baoZi;}@Overridepublic Cake createCake(String type) {Cake cake=null;switch (type){case "apple":cake=new BJAppleCake("北京苹果蛋糕");break;case "pear":cake=new BJPearCake("北京梨味蛋糕");default:break;}return cake;}
}
Test:
//4.抽象工厂模式
@Test
void abstractFactory(){AbstractFactory factory=new BJFactory();Cake apple = factory.createCake("apple");BaoZi pork = factory.createBaoZi("pork");apple.prepare();apple.make();apple.bake();apple.sale();pork.prepare();pork.make();pork.braise();pork.sale();
}
5.1 简单工厂模式
优点:
简单工厂模式实现简单,易于理解和使用; 可以对对象的创建进行集中管理,客户端和具体实现解耦。
缺点:工厂类负责创建所有对象,如果需要添加新类型的产品,则需要修改工厂类的代码,这违反了开闭原则; 工厂类职责过重,导致单一职责原则被破坏。
适用场景:工厂类负责创建的对象较少,客户端不需要知道对象的创建过程; 客户端需要根据传递的参数来获取对应的对象。
5.2 方法工厂模式
优点:
方法工厂模式具有良好的可扩展性,如果需要添加新类型的产品,只需要添加对应的工厂方法即可;
与简单工厂模式相比,方法工厂模式更符合开闭原则和单一职责原则。
缺点:需要客户端自行选择使用哪个工厂方法,不能像简单工厂模式那样直接传参获取对应对象,因此对客户端的编写有一定要求。 适用场景:
应用中需要创建的对象较少,但是需要具备良好的可扩展性; 客户端可以自行选择创建哪种对象。
5.3 抽象工厂
优点:
抽象工厂模式可以创建多个产品族的产品,这些产品之间有相互依赖或约束关系,有助于保持系统的一致性和稳定性;
客户端与具体产品解耦,通过产品族的方式进行管理。
缺点:抽象工厂模式增加了系统的抽象性和理解难度,不易于理解和修改; 新增产品族时需要修改工厂接口、工厂实现类和产品类,增加了系统的复杂性。
适用场景:系统需要一系列相互依赖或约束的产品; 客户端不需要知道具体产品的创建过程,只需要知道产品族即可。
相关文章:
3、设计模式之工厂模式2(Factory)
一、什么是工厂模式 工厂模式属于创建型设计模式,它用于解耦对象的创建和使用。通常情况下,我们创建对象时需要使用new操作符,但是使用new操作符创建对象会使代码具有耦合性。工厂模式通过提供一个公共的接口,使得我们可以在不暴露…...
npm、nodejs和vue之间关系和区别介绍
本文讲解npm、Node.js和Vue.js这三者之间的关系和区别,以及它们各自的特点。 首先,让我们来了解一下Node.js。 **Node.js** 是一个开源的服务器端运行环境,它允许开发者使用JavaScript来编写服务器端的代码。在传统的Web开发中&#…...
DM数据库安装(Windows)
先解压安装包 点击setup安装 下一步 勾选接受然后下一步 下一步 选择典型安装下一步 下一步 搜索DM数据库配置助手然后一直下一步 然后搜索DM管理工具 登录 登录成功 widows版本安装成功...
Python的asyncio 多线程
-- 多线程、进程、协程是什么就不讲了,(就是你理解的一边呼吸,一边看文章) 仅解决问题的话,下边两篇不用看, Python 中的 async await 概念-CSDN博客 再深一点的看这个 Python中的多线程、进程、协程、…...
【分类讨论】【解析几何】【 数学】【推荐】1330. 翻转子数组得到最大的数组值
作者推荐 视频算法专题 本文涉及知识点 分类讨论 解析几何 LeetCode1330. 翻转子数组得到最大的数组值 给你一个整数数组 nums 。「数组值」定义为所有满足 0 < i < nums.length-1 的 |nums[i]-nums[i1]| 的和。 你可以选择给定数组的任意子数组,并将该子…...
一文了解Spring的SPI机制
文章目录 一文了解Spring的SPI机制Java SPIServiceLoader Spring SPISpringboot利用Spring SPI开发starter 一文了解Spring的SPI机制 Java SPI SPI 全称 Service Provider Interface ,是 Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用…...
django根据时间(年月日)动态修改表名--方法一
方法一: 第一步:在models创建一个类,里边存放数据表中需要的字段,如下 class TemplateModel(models.Model):NowTime models.CharField(max_length5)name models.CharFiedld(max_length5)class Meta:abstract True # 基础类设…...
实现基本的登录功能
一、登录功能的前端处理过程 1、导入项目所需的图片和CSS等静态文件 参考代码存放client节点的/opt/code目录下 执行如下命令: [rootclient ~]# cp -r /opt/code/kongguan_web/src/assets/* /root/kongguan_web/src/assets/ 将参考代码中的css、icon、images等文…...
Java线程池实现原理及其在美团业务中的实践
随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流。使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器。 J.U.C提供的线程池:ThreadPoolExecutor类,帮助开发人员管理线程并方便地执行并行任务。了解并合理…...
让AI给你写代码(四)—— 初步利用LangChain Agent根据输入生成,保存,执行
要进一步提升智能编码助手的效率,我觉得需要做到两点 1) 进一步让主人聚焦于设计输入以及结果验证的循环 2) 进一步让智能编码助手聚焦于代码实现和程序流程(保存、打开,修订、执行、合并…) 正好接触到LLM…...
Flutter does not exist
Flutter does not exist 原因:Generated.config 配置文件内路径缺失 原因:Flutter SDK缺失 通过配置文件查到Flutter SDK在本地的存放位置FLUTTER_FRAMEWORK_DIR/Users/haijunyan/Documents/flutter/bin/cache/artifacts/engine/ios 真机所需…...
AIX上安装gcc和g++
AIX的iso镜像中没有gcc的软件包,需要我们自己下载,我们可以在 Index of /download/rpmdb/deplists/aix72 下载对应gcc和g版本的依赖文件deps 我们使用的是4.9.4版本的软件包 我们首先安装gcc,在http://www.oss4aix.org/download/everythi…...
js实现扫描线填色算法使用canvas展示
算法原理 扫描线填色算法的基本思想是:用水平扫描线从上到下扫描由点线段构成的多段构成的多边形。每根扫描线与多边形各边产生一系列交点。将这些交点按照x坐标进行分类,将分类后的交点成对取出,作为两个端点,以所填的色彩画水平…...
考研模拟面试-题目【攻略】
考研模拟面试-题目【攻略】 前言版权推荐考研模拟面试-题目前面的问题通用问题专业题数据结构计算机网络操作系统数据库网络安全 手写题数据结构操作系统计算机网络 代码题基础代码题其他代码题 后面的问题补充题目 最后 前言 2023-10-19 12:00:57 以下内容源自《考研模拟面试…...
Frostmourne - Elasticsearch源日志告警配置
简介 配置Frostmourne 接入Elasticsearch源进行日志匹配告警,并静默规则,告警消息发送到企业微信,告警信息使用Markdown。 部署安装教程查看: https://songxwn.com/frostmourne_install ELK 安装教程:https://songx…...
GPT出现Too many requests in 1 hour. Try again later.
换节点 这个就不用多说了,你都可以上GPT帐号了,哈…… 清除cooki 然后退出账号,重新登录即可...
python爬虫实战——小红书
目录 1、博主页面分析 2、在控制台预先获取所有作品页的URL 3、在 Python 中读入该文件并做准备工作 4、处理图文类型作品 5、处理视频类型作品 6、异常访问而被中断的现象 7、完整参考代码 任务:在 win 环境下,利用 Python、webdriver、JavaS…...
Linux信号机制
目录 一、信号的概念 二、定时器 1. alarm函数 2. setitimer函数 3.signal和sigaction函数 三、使用SIGCHLD信号实现回收子进程 一、信号的概念 概念:信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式 。所有信号的产生及处理全部都是由内…...
区块链技术中的共识机制算法:以权益证明(PoS)为例
引言: 在区块链技术的演进过程中,共识机制算法扮演着至关重要的角色。除了广为人知的工作量证明(PoW)外,权益证明(Proof of Stake,PoS)也是近年来备受关注的一种共识算法。 …...
19113133262(微信同号)【征稿进行时|见刊、检索快速稳定】2024年区块链、物联网与复合材料与国际学术会议 (ICBITC 2024)
【征稿进行时|见刊、检索快速稳定】2024年区块链、物联网与复合材料与国际学术会议 (ICBITC 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 区块链: 区块链技术和系统 分布式一致性算法和协议 块链性能 信息储存系统 区块链可扩展性 区块…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
