java设计模式学习之【单例模式】
文章目录
- 引言
- 单例模式简介
- 定义与用途
- 实现方式:
- 饿汉式
- 懒汉式
- UML
- 使用场景
- 优势与劣势
- 单例模式在spring中的应用
- 饿汉式实现
- 懒汉式实现
- 数据库连接示例
- 代码地址
引言
单例模式是一种常用的设计模式,用于确保在一个程序中一个类只有一个实例,并且提供一个全局访问点。这种模式在需要严格控制资源访问和分配的情况下非常有用。
单例模式简介
定义与用途
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这个模式经常用于控制资源的访问,如数据库连接或文件系统。
实现方式:
单例模式通常涉及以下几个关键步骤:
- 将构造函数设置为私有,防止外部通过new关键字创建实例。
- 在类内部创建一个类的实例。
- 提供一个公开的静态方法,供外部获取这个唯一的实例。
饿汉式
在类加载时就创建实例。这种方式是线程安全的,但可能会增加内存负担,因为实例不管是否需要都会被创建。
懒汉式
在第一次需要实例时才创建。这种方式可以节省资源,但需要考虑多线程环境下的线程安全问题。
UML

使用场景
- 资源共享控制:如数据库连接池或配置管理。
- 单一责任对象:当一个对象需要负责系统中的重要操作时。
- 节约资源:避免频繁地创建和销毁对象。
优势与劣势
- 优势
资源节约:减少了对象创建和销毁的开销。
全局访问:提供全局的访问点,易于管理。 - 劣势
全局依赖:过度使用可能导致代码之间的紧密耦合。
多线程问题:在多线程环境下可能会面临同步问题。
单例模式在spring中的应用
单例模式在Spring框架中的应用是其核心功能之一,特别体现在Spring的Bean容器管理中。在Spring框架中,单例模式的应用主要集中在以下几个方面:
Bean的默认作用域:
在Spring中,默认情况下,所有在Spring配置文件中定义的Bean都是以单例模式创建的。这意味着无论应用中有多少次对特定Bean的请求,Spring容器都会返回同一个Bean实例。
这种方式有助于节省资源,因为相同的Bean不会被多次创建。BeanFactory和ApplicationContext:
Spring的BeanFactory和ApplicationContext提供了Bean的创建和管理机制。它们作为Bean的容器,负责实例化、配置和组装Bean。
这些容器自身也是以单例模式运行的,确保整个应用中有一个统一的Bean管理中心。单例Bean的线程安全:
虽然单例Bean在Spring中只实例化一次,但Spring并不保证单例Bean是线程安全的。这意味着Bean的线程安全性依赖于其自身的实现。
在设计单例Bean时,需要考虑其在多线程环境下的行为,确保状态管理的正确性。单例模式与依赖注入(DI):
Spring使用依赖注入(DI)机制来管理Bean之间的依赖关系。在单例模式下,依赖注入确保相同的Bean实例被注入到其他需要它的Bean中。
这种机制简化了对象之间的关系,并提高了代码的可测试性和可维护性。配置与管理:
Spring的单例模式允许集中管理Bean的配置。由于每个Bean只有一个实例,因此其配置和属性只需要设置一次,而无需在每次使用时重新配置。
这对于管理大型应用中的配置和属性尤其有用,可以提高效率和一致性。
饿汉式实现
public class A {private static A obj = new A(); // 类加载时即创建实例private A() {} // 私有构造函数public static A getA() {return obj;}public void doSomething() {// 方法实现}}
懒汉式实现
public class A {private static A obj;private A() {} // 私有构造函数public static synchronized A getA() {if (obj == null) {obj = new A(); // 第一次调用时创建实例}return obj;}public void doSomething() {// 方法实现}
}
数据库连接示例
我们将通过创建一个JDBCSingleton类来展示单例设计模式的一个实际应用。这个类将被用于数据库操作,保证整个应用中只有一个数据库连接实例。
JDBCSingleton 类设计
JDBCSingleton类将包含:
- 一个私有构造函数,防止外部直接实例化。
- 一个私有静态实例jdbc,这是其自身的单一实例。
- 一个公共静态方法,允许外部世界获取这个静态实例。

假设我们已经在MySQL数据库中创建了一个名为userdata的表,它包含三个字段:uid、uname和upassword。数据库名称为ashwinirajput,用户名为root,密码为ashwini。
JDBCSingleton
public class JDBCSingleton {// 静态成员仅持有JDBCSingleton类的一个实例private static JDBCSingleton jdbc;// 私有构造器防止其他类实例化private JDBCSingleton() { }// 提供全局访问点public static JDBCSingleton getInstance() {if (jdbc == null) {jdbc = new JDBCSingleton();}return jdbc;}// 获取连接以进行插入、查看等操作private static Connection getConnection() throws ClassNotFoundException, SQLException {Connection con = null;Class.forName("com.mysql.jdbc.Driver");con = DriverManager.getConnection("jdbc:mysql://localhost:3306/ashwanirajput", "root", "ashwani");return con;}// 向数据库中插入记录public int insert(String name, String pass) throws SQLException {Connection c = null;PreparedStatement ps = null;int recordCounter = 0;try {c = getConnection();ps = c.prepareStatement("insert into userdata(uname, upassword) values(?, ?)");ps.setString(1, name);ps.setString(2, pass);recordCounter = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {if (ps != null) {ps.close();}if (c != null) {c.close();}}return recordCounter;}// 从数据库中查看数据public void view(String name) throws SQLException {Connection con = null;PreparedStatement ps = null;ResultSet rs = null;try {con = this.getConnection();ps = con.prepareStatement("select * from userdata where uname = ?");ps.setString(1, name);rs = ps.executeQuery();while (rs.next()) {System.out.println("姓名: " + rs.getString(2) + "\t" + "密码: " + rs.getString(3));}} catch (Exception e) {System.out.println(e);} finally {if (rs != null) {rs.close();}if (ps != null) {ps.close();}if (con != null) {con.close();}}}// 更新给定用户名的密码public int update(String name, String password) throws SQLException {Connection c = null;PreparedStatement ps = null;int recordCounter = 0;try {c = this.getConnection();ps = c.prepareStatement("update userdata set upassword = ? where uname = '" + name + "'");ps.setString(1, password);recordCounter = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {if (ps != null) {ps.close();}if (c != null) {c.close();}}return recordCounter;}// 从数据库删除数据public int delete(int userid) throws SQLException {Connection c = null;PreparedStatement ps = null;int recordCounter = 0;try {c = getConnection();ps = c.prepareStatement("delete from userdata where uid = '" + userid + "'");recordCounter = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {if (ps != null) {ps.close();}if (c != null) {c.close();}}return recordCounter;}}
JDBCSingletonDemo
public class JDBCSingletonDemo {static int count = 1;static int choice;public static void main(String[] args) throws IOException {JDBCSingleton jdbc = JDBCSingleton.getInstance();BufferedReader br = new BufferedReader(new InputStreamReader(System.in));do {System.out.println("数据库操作");System.out.println("---------------------");System.out.println("1. 插入");System.out.println("2. 查看");System.out.println("3. 删除");System.out.println("4. 更新");System.out.println("5. 退出");System.out.print("\n请输入你想在数据库中执行的操作: ");choice = Integer.parseInt(br.readLine());switch (choice) {case 1: {System.out.print("输入要插入数据库的用户名: ");String username = br.readLine();System.out.print("输入要插入数据库的密码: ");String password = br.readLine();try {int i = jdbc.insert(username, password);if (i > 0) {System.out.println("第 " + (count++) + " 条数据已成功插入");} else {System.out.println("数据未插入");}} catch (Exception e) {System.out.println(e);}System.out.println("按回车键继续...");System.in.read();break;}case 2: {System.out.print("输入要查看的用户名: ");String username = br.readLine();try {jdbc.view(username);} catch (SQLException e) {System.out.println(e);}System.out.println("按回车键继续...");System.in.read();break;}case 3: {System.out.print("输入要删除的用户ID: ");int userid = Integer.parseInt(br.readLine());try {int i = jdbc.delete(userid);if (i > 0) {System.out.println("第 " + (count++) + " 条数据已成功删除");} else {System.out.println("数据未删除");}} catch (Exception e) {System.out.println(e);}System.out.println("按回车键继续...");System.in.read();break;}case 4: {System.out.print("输入要更新的用户名: ");String username = br.readLine();System.out.print("输入新密码: ");String password = br.readLine();try {int i = jdbc.update(username, password);if (i > 0) {System.out.println("第 " + (count++) + " 条数据已成功更新");}} catch (Exception e) {System.out.println(e);}System.out.println("按回车键继续...");System.in.read();break;}default:return;}} while (choice != 5);}
}
这个示例展示了如何在实际应用中使用单例模式来创建和管理数据库连接。通过这种方式,可以确保应用程序中的所有组件都使用相同的数据库连接实例,从而提高了效率和一致性。同时,这也减少了数据库连接的开销,因为连接实例只被创建一次并在整个应用中复用。
运行代码:

代码地址
23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern
相关文章:
java设计模式学习之【单例模式】
文章目录 引言单例模式简介定义与用途实现方式:饿汉式懒汉式 UML 使用场景优势与劣势单例模式在spring中的应用饿汉式实现懒汉式实现数据库连接示例代码地址 引言 单例模式是一种常用的设计模式,用于确保在一个程序中一个类只有一个实例,并且…...
UWB高精度定位系统项目源码
在现代社会中,精准定位技术对于各行各业都至关重要。为了满足对高精度定位的需求,超宽带(Ultra-Wideband, UWB)技术应运而生。UWB高精度定位系统以其出色的定位精度和多样化的应用领域而备受关注。本文将深入探讨UWB高精度定位系统…...
WPF Live Charts2 自学笔记
文章目录 前言实现效果微软平台的历史问题 WPF 项目搭建Nuget添加额外框架添加项目初始化livecharts配置其它LiveCharts2 案例简单案例Demo示例ViewViewModel GPU渲染 Github地址仓库 前言 LiveChart 是C# 上面很受欢迎的统计图 UI控件。最近在学WPFhalcon开发,想想…...
大小堆的实现(C语言)
目录 前言 一种完全二叉树:堆 堆的概念 堆的性质 建堆的时间复杂度 建堆的空间复杂度: 小堆的实现 必要补充 堆的初始化 堆的销毁 向上调整算法 堆的插入 向下调整算法 堆的删除 获取堆顶元素 获取堆中元素个数 堆的判空 最终代码 He…...
Linux系统之centos7编译安装Python 3.8
前言 CentOS (Community Enterprise Operating System) 是一种基于 Red Hat Enterprise Linux (RHEL) 进行源代码再编译并免费提供给用户的 Linux 操作系统。 CentOS 7 采用了最新的技术和软件包,并提供了强大的功能和稳定性。它适用于各种服务器和工作站应用场景&a…...
Lambda表达式与方法引用
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 引子 先来看一个案例 …...
二维数组处理(一)
输入整型二维数组a(5行5列),完成如下要求: 输出二维数组a。 将a的第2行和第4行元素对调后,形成新的二维数组a并按行输出,每个元素之间隔一个空格。(行号从0开始计算)。 用对角线(指二维数组左…...
基于JNI实现调用C++ SDK
基于JNI实现调用C SDK 背景分析解决实践 背景 上篇文章总结了几种Java项目调用C/C SDK项目方法,在逐一实践、踩坑后,最终还是敲定采用 JNI 方式进行实现。在文章开始的过程,会先大概讲讲笔者遇到的情况,因为封装方式需要根据实际…...
计算机组成原理笔记——存储器(静态RAM和动态RAM的区别,动态RAM的刷新, ROM……)
■ 随机存取存储器 ■ 1.随机存取存储器:按存储信息的原理不同分为:静态RAM和动态RAM 2.静态RAM(SRAM):用触发器工作原理存储信息,但电源掉电时,存储信息会丢失具有易失性。 3.存储器的基本单元…...
企业计算机服务器locked1勒索病毒数据恢复,locked1勒索病毒解密流程
随着计算机技术的不断发展,越来越多的企业走向数字化办公时代,计算机技术为企业的生产运营提供了有利条件,但也为企业带来了网络安全威胁。在本月,云天数据恢复中心陆续接到很多企业的求助,企业的速达办公软件遭到了lo…...
Session 与 JWT 的对决:谁是身份验证的王者? (下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
论文笔记:Confidential Assets
Confidential Assets 描述了一种称为“保密交易”的方案,该方案模糊了所有UTXO的金额,同时保持了不创建或销毁硬币的公共可验证性。进一步将此方案扩展到“保密资产”,一种单一的基于区块链的分类帐可以跟踪多种资产类型的方案。将保密交易扩…...
Docker下搭建MySQL主从复制
目录 主从复制简介 主从复制搭建 主从复制简介 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数 据库一般是准实时的业务数据库。 主从复制的作用 做数据的热备。作为后备数据库,主数据库服务器故…...
VBA数据库解决方案第七讲:如何利用Recordset对象打开数据库的数据记录集
《VBA数据库解决方案》教程(版权10090845)是我推出的第二套教程,目前已经是第二版修订了。这套教程定位于中级,是学完字典后的另一个专题讲解。数据库是数据处理的利器,教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...
内部培训平台的系统 PlayEdu搭建私有化内部培训平台
PlayEdu是由白书科技团队多年经营的线上教育系统,专为企业提供的全新企业培训方案 我们的目标是为更多的企业机构搭建私有化内部培训平台,以满足不断增长的培训需求 通过PlayEdu,企业可以有效地组织和管理培训资源,提供高质量的…...
Elasticsearch 相似度评分模型介绍
前言 Elasticsearch 是基于 Lucene 的世界范围内最流行的全文检索框架,其文档相似度算法包含 TF/IDF 和 BM25,从 ES 5.0开始 BM25 算法已经成为 ES 默认的相似度评分模块。 TF-IDF 与 BM25 的区别 TF-IDF 和 BM25 都是计算文本相似性的常用算法。TF-ID…...
视频生成的发展史及其原理解析:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0
前言 考虑到文生视频开始爆发,比如11月份就是文生视频最火爆的一个月 11月3日,Runway的Gen-2发布里程碑式更新,支持4K超逼真的清晰度作品(runway是Stable Diffusion最早版本的开发商,Stability AI则开发的SD后续版本)11月16日&a…...
SQL Server 2016(基本概念和命令)
1、文件类型。 【1】主数据文件:数据库的启动信息。扩展名为".mdf"。 【2】次要(辅助)数据文件:主数据之外的数据都是次要数据文件。扩展名为".ndf"。 【3】事务日志文件:包含恢复数据库的所有事务…...
Linux C语言 30-套接字操作
Linux C语言 30-套接字操作 本节关键字:C语言 网络通信、套接字操作、TCP、UDP、服务端、客户端 相关C库函数:socket, bind, listen, accept, setsockopt, recv, send, recvfrom, sendto, close 什么是网络通信? 通信是人与人之间通过某种…...
RPC和REST对比
RPC和REST对比 参考学习 RPC 和 REST 之间有什么区别? 当我们对比RPC和REST时,其实是在对比RPC风格的API和REST风格的API,后者通常成为RESTful API。 远程过程调用(RPC)和 REST 是 API 设计中的两种架构风格。API …...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
