了解单例模式,工厂模式(简单易懂)
文章目录
- 单例模式
- 饿汉模式
- 懒汉模式
- 对比
- 工厂模式
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 对比
单例模式
- 什么是单例? 系统运行期间有且仅有一个实例。
- 为什么要有单例?系统中的一些对象只需要初始化一次即可,例如:KTV中的播放器或者初始化系统参数
- 单例模式的要求:
- 一个类只有一个实例 只提供私有的构造器。
private SingletonClass(){ }
- 必须自己创建这个实例 定义该类的静态私有对象。
private static SingletonClass single;
- 必须自己向系统提供这个实例。 创建一个公共的静态方法,返回这个实例。
public static SingletonClass getSingleton(){if(single==null){initSingleton();}return single; }
饿汉模式
不管你用不用我都给你创建这个实例。(官方语言:在类加载的时候创建这个实例)。 天然线程安全的,每个类中获取这个对象的耗时基本一样
下面是饿汉模式,使用静态内部类实现延迟加载。
public class SingleTon {private SingleTon() {}private static SingleTon singleTon;// 静态内部类public static class SingletonHelper{private static final SingleTon INSTANCE = new SingleTon();}public static SingleTon getSingleTon() {singleTon = SingletonHelper.INSTANCE;return singleTon;}}
懒汉模式
在你调用的时候才创建这个实例。不是线程安全,第一次获取此对象会耗时较多
- 线程安全问题
- double check 加锁优化
- 编译器(JIT),CPU有可能对指令执行重新排序,导致使用到尚未初始化的实例(nullpointException),可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排。
/*** 手写一个单例模式*/
public class SingletonClass {// 1.私有化构造方法,收回创建实例的权限private SingletonClass(){}// 2.自己声明这个实例对象private volatile static SingletonClass singletonClass;// 3.向系统提供一个公共的方法,获取这个实例public static SingletonClass getInstance(){if(singletonClass==null){ // 为空才加同步锁,锁的范围越小越好synchronized (SingletonClass.class){if(singletonClass==null){ // 判断是否为空,防止实例化两次singletonClass = new SingletonClass();// 字节码 其中2和3可能存在重排的问题,如果3在前,在多线程的情况下会出现空指针// 1.分配空间// 2.初始化// 3.引用赋值}}}return singletonClass;}}
对比
- 线程安全:饿汉式天生就是线程安全的,懒汉式本身是非线程安全的。
- 资源加载和性能:饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
工厂模式
- 什么是工厂? 将对象的创建过程封装在一个工厂类中,通过调用工厂类的方法来获取对象实例,而不需要直接使用new关键字来创建对象
- 为什么要有工厂模式? 工厂模式能够提供更好的代码组织结构、更好的封装性、更好的可扩展性和更好的解耦性,从而提高了代码的质量和可维护性
- 工厂模式的要求
- 抽象产品:定义产品的共同接口或抽象类,描述产品的特征和行为。
- 具体产品:实现抽象产品接口或继承抽象产品类,是工厂创建的目标对象。
// 抽象产品接口
public interface Product {void operation1();void operation2();
}// 具体类A
public class ConcreteProductA implements Product {@Overridepublic void operation1() {// 具体类A的操作1}@Overridepublic void operation2() {// 具体类A的操作2}
}// 具体类B
public class ConcreteProductB implements Product {@Overridepublic void operation1() {// 具体类B的操作1}@Overridepublic void operation2() {// 具体类B的操作2}
}
- 抽象工厂:定义工厂的共同接口或抽象类,描述创建产品的方法。
- 具体工厂:实现抽象工厂接口或继承抽象工厂类,负责实际创建产品的类。
- 客户端:使用工厂创建产品的代码,通过工厂接口来创建所需的产品对象。
# 定义抽象工厂接口
class AbstractFactory:def create_product_a(self):passdef create_product_b(self):pass# 实现具体的工厂类
class ConcreteFactory1(AbstractFactory):def create_product_a(self):return ProductA1()def create_product_b(self):return ProductB1()class ConcreteFactory2(AbstractFactory):def create_product_a(self):return ProductA2()def create_product_b(self):return ProductB2()# 定义产品接口
class AbstractProductA:def do_something(self):passclass AbstractProductB:def do_something(self):pass# 实现具体类
class ProductA1(AbstractProductA):def do_something(self):print("Product A1")class ProductA2(AbstractProductA):def do_something(self):print("Product A2")class ProductB1(AbstractProductB):def do_something(self):print("Product B1")class ProductB2(AbstractProductB):def do_something(self):print("Product B2")# 客户端代码
def client_code(factory):product_a = factory.create_product_a()product_b = factory.create_product_b()product_a.do_something()product_b.do_something()# 使用具体工厂1
factory1 = ConcreteFactory1()
client_code(factory1)# 使用具体工厂2
factory2 = ConcreteFactory2()
client_code(factory2)
简单工厂模式(Simple Factory Pattern)
简单工厂模式又称为静态工厂模式,它由一个工厂类来负责创建所有的产品对象。客户端只需要通过工厂类来创建产品对象,而不需要直接实例化具体产品类。简单工厂模式的核心是一个工厂类,它包含一个创建产品的方法,根据客户端传入的参数来决定创建哪种产品。
# 定义产品接口
class Product:def show(self):pass# 定义具体类A,实现接口
class ConcreteProductA(Product):def show(self):print("Concrete Product A")# 定义具体类B,实现接口
class ConcreteProductB(Product):def show(self):print("Concrete Product B")# 定义静态工厂类
class StaticFactory:@staticmethoddef create_product(product_type):if product_type == "A":return ConcreteProductA()elif product_type == "B":return ConcreteProductB()else:raise ValueError("Invalid product type")# 客户端代码
if __name__ == "__main__":product_a = StaticFactory.create_product("A") # 使用静态工厂类创建具体Aproduct_a.show() # 调用具体A的方法,输出 "Concrete Product A"product_b = StaticFactory.create_product("B") # 使用静态工厂类创建具体Bproduct_b.show() # 调用具体B的方法,输出 "Concrete Product B"
工厂方法模式(Factory Method Pattern)
工厂方法模式将具体产品的创建过程延迟到子类中进行,每个具体产品都对应一个具体工厂类。客户端通过调用工厂方法来创建产品对象,工厂方法由子类实现,以创建对应的具体产品对象。
// 抽象类
public abstract class Product {public abstract void use();
}// 具体类A
public class ConcreteProductA extends Product {@Overridepublic void use() {System.out.println("使用具体类A");}
}// 具体类B
public class ConcreteProductB extends Product {@Overridepublic void use() {System.out.println("使用具体类B");}
}// 抽象工厂类
public abstract class Factory {public abstract Product createProduct();
}// 工厂类A
public class ConcreteFactoryA extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 工厂类B
public class ConcreteFactoryB extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客户端代码
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.use();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.use();}
}
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定其具体类。抽象工厂模式包含一个抽象工厂接口,定义了用于创建产品对象的方法,具体工厂类实现了抽象工厂接口,并负责创建一系列相关产品。每个具体工厂类都对应于一个产品族,可以创建该产品族的多个产品。
// 定义抽象A
interface AbstractProductA {void operationA();
}// 定义具体A1
class ConcreteProductA1 implements AbstractProductA {public void operationA() {System.out.println("Product A1");}
}// 定义具体A2
class ConcreteProductA2 implements AbstractProductA {public void operationA() {System.out.println("Product A2");}
}// 定义抽象B
interface AbstractProductB {void operationB();
}// 定义具体B1
class ConcreteProductB1 implements AbstractProductB {public void operationB() {System.out.println("Product B1");}
}// 定义具体B2
class ConcreteProductB2 implements AbstractProductB {public void operationB() {System.out.println("Product B2");}
}// 定义抽象工厂
interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}// 定义具体工厂1
class ConcreteFactory1 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA1();}public AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 定义具体工厂2
class ConcreteFactory2 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA2();}public AbstractProductB createProductB() {return new ConcreteProductB2();}
}// 调用方
public class Client {public static void main(String[] args) {// 创建工厂1AbstractFactory factory1 = new ConcreteFactory1();// 使用工厂1创建A和BAbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();// 创建工厂2AbstractFactory factory2 = new ConcreteFactory2();// 使用工厂2创建A和BAbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}
对比
- 简单工厂模式适用于对象种类较少且不会频繁变化的情况,工厂方法模式适用于对象种类较多且可能会有新产品增加的情况,抽象工厂模式适用于创建一组相关或相互依赖的产品且可能会有新的产品组合增加的情况。根据具体的需求和场景,选择适合的工厂模式可以提高代码的灵活性和可维护性。
- 简单工厂模式是通过一个工厂类来创建所有的产品对象,根据不同的参数返回不同的具体产品对象。在多线程环境下,如果多个线程同时调用工厂的创建方法,可能会导致线程安全问题。解决这个问题的一种方式是在工厂类的创建方法上加锁,保证同一时间只有一个线程能够调用该方法。
- 工厂方法模式将产品的创建延迟到子类中,每个产品有一个对应的工厂类来创建。在多线程环境下,每个线程独立使用各自的工厂类创建产品对象,不存在线程安全问题。不同的线程可以并发调用不同的工厂类创建产品,互不干扰。
- 抽象工厂模式通过提供一个接口来创建一系列相关或依赖对象的家族,而不需要指定具体的类。在多线程环境下,如果多个线程同时调用不同的具体工厂类创建产品对象,也不存在线程安全问题。不同的线程可以并发调用不同的具体工厂类创建产品,互不干扰。
相关文章:
了解单例模式,工厂模式(简单易懂)
文章目录 单例模式饿汉模式懒汉模式对比 工厂模式简单工厂模式(Simple Factory Pattern)工厂方法模式(Factory Method Pattern)抽象工厂模式(Abstract Factory Pattern)对比 单例模式 什么是单例ÿ…...

【中危】 Apache NiFi 连接 URL 验证绕过漏洞 (CVE-2023-40037)
漏洞描述 Apache NiFi 是一个开源的数据流处理和自动化工具。 在受影响版本中,由于多个Processors和Controller Services在配置JDBC和JNDI JMS连接时对URL参数过滤不完全。使用startsWith方法过滤用户输入URL,导致过滤可以被绕过。攻击者可以通过构造特…...

【Git版本控制工具使用---讲解一】
Git版本控制工具使用 安装设置用户名签名和邮箱Git常用的命令 初始化本地库查看本地状态Git 命令添加暂存区提交本地库查看版本信息修改文件版本穿梭 安装 首先根据自身电脑的配置选择性的安装是32位的还是64位的Git版本控制工具 我这边安装的是64位的 以下是我安装的时候的过…...

NLP | 基于LLMs的文本分类任务
比赛链接:讯飞开放平台 来源:DataWhale AI夏令营3(NLP) Roberta-base(BERT的改进) ①Roberta在预训练的阶段中没有对下一句话进行预测(NSP) ②采用了动态掩码 ③使用字符级和词级…...

攻防世界-base÷4
原题 解题思路 base644,莫不是base16,base16解码网站: 千千秀字...

【Java转Go】快速上手学习笔记(三)之基础篇二
【Java转Go】快速上手学习笔记(二)之基础篇一 了解了基本语法、基本数据类型这些使用,接下来我们来讲数组、切片、值传递、引用传递、指针类型、函数、map、结构体。 目录 数组和切片值传递、引用传递指针类型defer延迟执行函数map结构体匿名…...
【vue 引入pinia与pinia的详细使用】
vue引入pinia与使用 安装引入使用定义 store在组件中使用 store在插件中使用 store配置 store 总结 Pinia 是一个用于 Vue 3 的状态管理库,其设计目标是提供一个简单、一致的 API 和强类型支持。下面介绍如何引入 Pinia 并使用它。 安装 npm install pinia引入 在…...
USACO18DEC Fine Dining G
P5122 [USACO18DEC] Fine Dining G 题目大意 有一个由 n n n个点 m m m条边构成的无向连通图,这 n n n个点的编号为 1 1 1到 n n n。前 n − 1 n-1 n−1个点上都有一头奶牛,这些奶牛都要前往 n n n号点。第 i i i条边连接 a i a_i ai和 b i b_i bi…...
fckeditor编辑器的两种使用方法
需要的资源包我放我资源里了,不要积分 https://download.csdn.net/download/wybshyy/88245895 首先把FredCK.FCKeditorV2.dll添加到引用 具体方法如下,一个是客户端版本,一个是服务器端版本 客户端版本: <% Page Language…...
数据结构,查找算法(二分,分块,哈希)
一、查找算法 1、二分查找:(前提条件: 必须有序的序列) #include <stdio.h> //二分查找 value代表的是被查找的值 int findByHalf(int *p, int n, int value) {int low = 0;//low低int high = n-1;//high高int middle;//用来保存中间位置的下标while(low <= high…...

C++(Qt)软件调试---gdb调试入门用法(12)
gdb调试—入门用法(1) 文章目录 gdb调试---入门用法(1)1、前言1.1 什么是GDB1.2 为什么要学习GDB1.3 主要内容1.4 GDB资料 2、C/C开发调试环境准备3、gdb启动调试1.1 启动调试并传入参数1.2 附加到进程1.3 过程执行1.4 退出调试 4…...

shell和Python 两种方法分别画 iostat的监控图
在服务器存储的测试中,经常需要看performance的性能曲线,这样最能直接观察HDD或者SSD的性能曲线。 如下这是一个针对HDD跑Fio读写的iostat监控log,下面介绍一下分别用shell 和Python3 写画iostat图的方法 1 shell脚本 环境:linux OS gnuplot工具 第一步 :解析iosta…...
设计模式(9)建造者模式
一、 1、概念:将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示。建造者模式主要用于创建一些复杂的对象,这些对象内部构建间的顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化;建造…...

PHP 创业感悟交流平台系统mysql数据库web结构apache计算机软件工程网页wamp
一、源码特点 PHP 创业感悟交流平台系统(含论坛)是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 源码下载: https://download.csdn.…...

工作流程引擎之flowable(集成springboot)
0、背景 现状:公司各部门业务系统有各自的工作流引擎,也有cross function的业务在不同系统或OA系统流转,没有统一的去规划布局统一的BPM解决方案,近期由于一个项目引发朝着整合统一的BPM方案,特了解一下市面上比较主流…...

leetcode54. 螺旋矩阵(java)
螺旋矩阵 题目描述解题 收缩法 上期经典算法 题目描述 难度 - 中等 原题链接 - leecode 54 螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例1: 输入:matrix [[1,2,3],[4,5,6],[7…...
go gorm 查询
定义model package mysqltestimport ("errors""fmt""gorm.io/gorm" )type Product struct {gorm.ModelID uint gorm:"primarykey"Name string gorm:"column:name"Price float64 gorm:"column:price_value&quo…...
Flutter GetXController 动态Tabbar 报错问题
场景: 1.Tabbar的内容是接口获取的 2. TabController? tabController;; 在onInit 方法中初始化tabbarController tabController TabController(initialIndex: 0, length: titleDataList.length, vsync: this); 这时候会报一个错误 Controllers l…...

Redis(缓存预热,缓存雪崩,缓存击穿,缓存穿透)
目录 一、缓存预热 二、缓存雪崩 三、缓存击穿 四、缓存穿透 一、缓存预热 开过车的都知道,冬天的时候启动我们的小汽车之后不要直接驾驶,先让车子发动机预热一段时间再启动。缓存预热是一样的道理。 缓存预热就是系统启动前,提前将相关的…...

UE4/5Niagara粒子特效学习(使用UE5.1,适合新手)
目录 创建空模板 创建粒子 粒子的基础属性 粒子的生命周期 颜色 大小设置 生成的位置 Skeletal Mesh Location的效果: Shape Location 添加速度 添加Noise力场 在生成中添加: 效果: 编辑 在更新中添加: 效果&…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...