了解单例模式,工厂模式(简单易懂)
文章目录
- 单例模式
- 饿汉模式
- 懒汉模式
- 对比
- 工厂模式
- 简单工厂模式(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力场 在生成中添加: 效果: 编辑 在更新中添加: 效果&…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
P10909 [蓝桥杯 2024 国 B] 立定跳远
# P10909 [蓝桥杯 2024 国 B] 立定跳远 ## 题目描述 在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 $n$ 个检查点 $a_1, a_2, \cdots , a_n$ 且 $a_i \ge a_{i−1} > 0$。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时࿰…...