单例模式详解:概念与实用技巧

目录

  • 单例模式
    • 单例模式结构
    • 单例模式适用场景
    • 单例模式优缺点
    • 练手题目
      • 题目描述
      • 输入描述
      • 输出描述
      • 输入示例
      • 输出示例
      • 提示信息
      • 题解

单例模式

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

  • 只有一个实例的意思是,在整个应用程序中,只存在该类的一个实例对象,而不是创建多个相同类型的对象。

  • 全局访问点的意思是,为了让其他类能够获取到这个唯一实例,该类提供了一个全局访问点(通常是一个静态方法),通过这个方法就能获得实例。

单例模式结构

  • 私有的构造函数:防止外部代码直接创建类的实例

  • 私有的静态实例变量:保存该类的唯一实例

  • 公有的静态方法:通过公有的静态方法来获取类的实例

在这里插入图片描述

单例模式通用代码

单例模式的实现方式有多种,包括懒汉式、饿汉式等。

  • 饿汉式指的是在类加载时就已经完成了实例的创建,不管后面创建的实例有没有使用,先创建再说,所以叫做 “饿汉”。

  • 而懒汉式指的是只有在请求实例时才会创建,如果在首次请求时还没有创建,就创建一个新的实例,如果已经创建,就返回已有的实例,意思就是需要使用了再创建,所以称为“懒汉”。

饿汉模式

//单例类通过'getSingleton(获取实例)'方法进行定义,让客户端全局获得该对象实例
public class Singleton{// 保存单例实例成员变量必须被声明为静态类型
private static final Singleton singleton=new Singleton();// 单例的构造函数必须永远是私有类型,以防止使用`new`运算符直接调用构造方法。限制产生多个对象
private Singleton(){}//通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;}
//类中其他方法,尽量是static
public static void doSomething(){}
}

懒汉模式

public class Singleton {private static Singleton instance;private Singleton() {// 私有构造方法,防止外部实例化}// 使用了同步关键字来确保线程安全, 可能会影响性能public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

在懒汉模式的基础上,可以使用双重检查锁来提高性能。

public class Singleton {private static volatile Singleton instance;private Singleton() {// 私有构造方法,防止外部实例化}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

有上限的多例模式,它是单例模式的一种扩展,采用有上限的多例模式,我们可以在设计时决定在内存中有多少个实例,方便系统进行扩展,修正单例可能存在的性能问题,提供系统的响应速度。

public class Singleton{private static int maxNum=3;//最多产生3个实例数量private static ArrayList<Singleton> List=new ArrayList<Singleton>();private static int count=0;//当前皇帝序列号static{for(int i=0;i<maxNum;i++){List.add(new Singleton());}}private Singleton(){}private static Singleton getInstance(){Random random=new Random();count=random.nextInt(maxNum);return List.get(count);}}

单例模式适用场景

  1. 如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。

    单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。 该方法可以创建一个新对象, 但如果该对象已经被创建, 则返回已有的对象。

  2. 如果你需要更加严格地控制全局变量, 可以使用单例模式。

    单例模式与全局变量不同, 它保证类只存在一个实例。 除了单例类自己以外, 无法通过任何方式替换缓存的实例。

在这里插入图片描述

识别方法: 单例可以通过返回相同缓存对象的静态构建方法来识别。

单例模式优缺点

单例模式优点:

  • 你可以保证一个类只有一个实例。

  • 你获得了一个指向该实例的全局访问节点。

  • 仅在首次请求单例对象时对其进行初始化。

单例模式缺点:

  • 违反了单一职责原则。 该模式同时解决了两个问题。

  • 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

  • 单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。

  • 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。

  • 单例的客户端代码单元测试可能会比较困难, 因为许多测试框架以基于继承的方式创建模拟对象。 由于单例类的构造函数是私有的, 而且绝大部分语言无法重写静态方法, 所以你需要想出仔细考虑模拟单例的方法。 要么干脆不编写测试代码, 或者不使用单例模式。

练手题目

题目描述

小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。(在整个购物过程中,小明只有一个购物车实例存在)。

输入描述

输入包含若干行,每行包含两部分信息,分别是商品名称和购买数量。商品名称和购买数量之间用空格隔开。

输出描述

输出包含小明购物车中的所有商品及其购买数量。每行输出一种商品的信息,格式为 “商品名称 购买数量”。

输入示例

Apple 3 Banana 2 Orange 5

输出示例

Apple 3 Banana 2 Orange 5

提示信息

本道题目请使用单例设计模式, 使用私有静态变量来保存购物车实例。 使用私有构造函数防止外部直接实例化。

题解

1.简单单例模式实现。

import java.util.Scanner;
import java.util.ArrayList;class ShoppingCart {private static ShoppingCart instance = new ShoppingCart();private static ArrayList<String> productNames = new ArrayList<>();private static ArrayList<Integer> productQuantities = new ArrayList<>();private ShoppingCart() {}public static ShoppingCart getInstance() {return instance;}public void Add(String name, int quantity) {productNames.add(name);productQuantities.add(quantity);System.out.println(name + " " + quantity);}
}public class Main {public static void main(String[] args) {ShoppingCart cart = ShoppingCart.getInstance();Scanner scanner = new Scanner(System.in);String inputLine;while (scanner.hasNextLine()) {inputLine = scanner.nextLine();if ("exit".equalsIgnoreCase(inputLine)) {break;}String[] parts = inputLine.split(" ");if (parts.length == 2) {String name = parts[0];int quantity;try {quantity = Integer.parseInt(parts[1]);cart.Add(name, quantity);} catch (NumberFormatException e) {System.out.println("输入错误,请重新输入");}} else {System.out.println("输入错误,请重新输入");}}scanner.close();}
}

2.在懒汉模式的基础上,可以使用双重检查锁来提高性能。

import java.util.Scanner;  
import java.util.ArrayList;  class ShoppingCart {// 购物车类的单例实例变量,使用volatile关键字确保线程安全private static volatile ShoppingCart instance;// 存储商品名称private static ArrayList<String> productNames = new ArrayList<>();// 存储商品数量private static ArrayList<Integer> productQuantities = new ArrayList<>();// 私有构造函数,防止外部直接创建ShoppingCart对象private ShoppingCart() {}// 获取购物车单例实例的方法,确保线程安全public static ShoppingCart getInstance() {if (instance == null) {synchronized (ShoppingCart.class) {if (instance == null) {instance = new ShoppingCart();}}}return instance;}// 添加商品到购物车的方法public void Add(String name, int quantity) {productNames.add(name); productQuantities.add(quantity); System.out.println(name + " " + quantity);}
}public class Main {public static void main(String[] args) {ShoppingCart cart = ShoppingCart.getInstance(); Scanner scanner = new Scanner(System.in);  String inputLine;// 循环读取用户输入,直到用户输入"exit"while (scanner.hasNextLine()) {inputLine = scanner.nextLine();if ("exit".equalsIgnoreCase(inputLine)) {break;}// 使用空格分割输入的字符串,获取商品名称和数量String[] parts = inputLine.split(" ");// 确保输入格式正确,即包含两个部分:商品名称和数量if (parts.length == 2) {// 商品名称String name = parts[0];  // 商品数量int quantity; try {// 将第二部分转换为整数quantity = Integer.parseInt(parts[1]);cart.Add(name, quantity);  } catch (NumberFormatException e) {// 如果转换失败,输出错误信息System.out.println("转换失败,请重新输入");}} else {// 如果输入格式不正确,输出错误信息System.out.println("如果输入格式不正确,请重新输入");}}scanner.close();}
}

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

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

相关文章

震惊!运气竟能如此放大!运气的惊人作用,你了解吗?

芒格&#xff1a;得到你想要的东西&#xff0c;最保险的办法&#xff0c;就是让自己配得上你想要的那个东西。今天仔细想了想这句话&#xff0c;他其实说的是无数成功人士的心声 —— “我配得上&#xff01;” 美剧《绝命毒师》有个导演叫文斯吉里根&#xff08;Vince Gilliga…

大疆2025校招内推

需要内推码的请留言哦 期待你的加入

windows@资源管理器中的地址栏@访问共享文件夹的各种方法@管理共享文件夹

文章目录 资源管理器中的地址栏可以访问什么访问共享文件夹&#x1f47a;UNC路径资源管理器打开共享文件夹纯命令行方式访问共享文件夹 共享文件夹相关操作查看所有已经共享的文件夹&#x1f47a;停止某个文件的共享 共享文件夹的访问控制补充匿名访问问题&#x1f60a;强制启用…

吴恩达深度学习笔记:机器学习策略(2)(ML Strategy (2)) 2.5-2.6

目录 第三门课 结构化机器学习项目&#xff08;Structuring Machine Learning Projects&#xff09;第二周&#xff1a;机器学习策略&#xff08;2&#xff09;(ML Strategy (2))2.5 数据分布不匹配时的偏差与方差的分析&#xff08;Bias and Variance with mismatched data di…

师从IEEE fellow|博士后加拿大阿尔伯塔大学成行

V老师指定申请加拿大&#xff0c;优先对方出资的博士后&#xff0c;如果外方无资助&#xff0c;也可以自筹经费&#xff0c;但要求必须是博士后头衔。最终我们为其落实了加拿大阿尔伯塔大学的postdoctoral fellow&#xff08;博士后研究员&#xff09;&#xff0c;尽管是无薪职…

2024亚太杯中文赛数学建模选题建议及各题思路来啦!

大家好呀&#xff0c;2024年第十四届APMCM亚太地区大学生数学建模竞赛&#xff08;中文赛项&#xff09;开始了&#xff0c;来说一下初步的选题建议吧&#xff1a; 首先定下主基调&#xff0c; 本次亚太杯推荐大家选择B题目。C题目难度较高&#xff0c;只建议用过kaiwu的队伍…

仓颉——申请内测、环境搭建、编译测试

2024年6月21日&#xff0c;华为仓颉正式公开发布。 不少同学看过仓颉白皮书后&#xff0c;都在找SDK从哪下载&#xff0c;HelloWorld怎么跑。仓颉公众号也及时发布了内测的方式&#xff0c;我也亲自走了一遍整个流程&#xff0c; 一&#xff0c;申请内测 关注“仓颉编程语言…

暗潮短视频:成都柏煜文化传媒有限公司

暗潮短视频&#xff1a;涌动的新媒体力量 在数字化时代的浪潮中&#xff0c;短视频以其独特的魅力和无限的潜力&#xff0c;迅速成为新媒体领域的一股强大力量。而在这片繁荣的短视频领域中&#xff0c;成都柏煜文化传媒有限公司“暗潮短视频”以其独特的定位和深邃的内容&…

Beyond Low-frequency Information in Graph Convolutional Networks

推荐指数: #paper/⭐⭐⭐ #paper/&#x1f4a1; 发表于:AAAI21 简称:FAGCL 问题提出背景: GCN常常使用低频信息,但是在现实中,不仅低频信息重要,高频信息页重要 如上图,随着类间链接的增加,低频信号的增强开始变弱,高频信号的增强开始增加. 作者贡献: 不仅低频信号重要,高…

智能井盖采集装置 开启井下安全新篇章

在现代城市的脉络之下&#xff0c;错综复杂的管网系统如同城市的血管&#xff0c;默默支撑着日常生活的有序进行。而管网的监测设备大多都安装在井下&#xff0c;如何给设备供电一直是一个难题&#xff0c;选用市电供电需经过多方审批&#xff0c;选用电池供电需要更换电池包&a…

MySQL表的练习

二、创建表 1、创建一个名称为db_system的数据库 create database db_system; 2、在该数据库下创建两张表&#xff0c;具体要求如下 员工表 user 字段 类型 约束 备注 id 整形 主键&#xff0c;自增长 id N…

权限控制权限控制权限控制权限控制权限控制

1.权限的分类 视频学习&#xff1a;https://www.bilibili.com/video/BV15Q4y1K79c/?spm_id_from333.337.search-card.all.click&vd_source386b4f5aae076490e1ad9b863a467f37 1.1 后端权限 1. 后端如何知道该请求是哪个用户发过来的 可以根据 cookie、session、token&a…

WIN32核心编程 - 进程操作(一) 进程基础 - 创建进程 - 进程句柄

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 进程基础 进程的定义与概念 进程的组成 创建进程 可执行文件 CreateProces 执行流程 GetStartupInfo 进程终止 进程句柄 创建进程 打开进程 进程提权 内核模拟 回溯对象 自身进…

SD NAND时序解析

一、SD NAND时序的重要性 在SD NAND的数据传输过程中&#xff0c;时序起着至关重要的作用。正确的时序确保了数据能够准确无误地在主机和SD NAND之间传输。 二、命令与读写时序 SD NAND的通信基于命令和数据传输&#xff0c;遵循以下时序规则&#xff1a; 命令与响应交互&…

安卓常用的控件

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 在Android开发中&#xff0c;控件&#xff08;也称为视图或控件组件&#xff09;是构建用户界面的基本元素。它们…

康姿百德磁性床垫好不好,效果怎么样靠谱吗

康姿百德典雅款床垫&#xff0c;打造舒适睡眠新体验 康姿百德床垫是打造舒适睡眠新体验的首选&#xff0c;其设计能够保护脊椎健康&#xff0c;舒展脊椎&#xff0c;让您享受一夜好眠。康姿百德床垫的面料选择也非常重要&#xff0c;其细腻亲肤的针织面料给您带来柔软舒适的触…

如何在操作使用ufw设置防火墙

UFW&#xff08;简单防火墙&#xff09;是用于管理iptables防火墙规则的用户友好型前端。它的主要目标是使iptables的管理更容易。 在学习Linux的时候大家一般都会关心命令&#xff0c;Posix API和桌面等&#xff0c;很少会去了解防护墙。其实除了一些网络安全厂商提供的付费防…

交互案例:5大经典交互效果

文件格式&#xff1a;.rp&#xff08;请与班主任联系获取原型文档&#xff09; 文件名称&#xff1a;Axure交互案例&#xff1a;5大经典交互实现 文件大小&#xff1a;78.5 MB 文档内容介绍 五大经典交互包括&#xff1a; 图片手风琴 图片悬浮放大 详细说明切换 图片全屏查…

上位机GUI 第三弹

&#x1f60a; &#x1f60a; &#x1f60a; 从协议层面讲&#xff0c;地质单元相当重要&#xff0c;调试模式,我只能义命令发送的索引码作为,每个设备的区分方式,调试的情况&#xff0c;不在设备上设置任何东西&#xff0c;开机访问地址和端口就能用 因为懒&#xff0c;直接将…

【代码随想录】【算法训练营】【第55天】 [42]接雨水 [84]柱状图中最大的矩形

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 55&#xff0c;又是一个周一&#xff0c;不能再坚持~ 题目详情 [42] 接雨水 题目描述 42 接雨水 解题思路 前提&#xff1a;雨水形成的情况是凹的, 需要前中后3个元素&#xff0c;计算该元…