设计模式 创建型 单例模式(Singleton Pattern)与 常见技术框架应用 解析

在这里插入图片描述

单例模式(Singleton Pattern)是一种创建型设计模式,旨在确保某个类在应用程序的生命周期内只有一个实例,并提供一个全局访问点来获取该实例。这种设计模式在需要控制资源访问、避免频繁创建和销毁对象的场景中尤为有用。

一、核心思想

单例模式的核心思想是限制类的实例化次数,确保整个应用程序中只有一个实例存在,并且这个实例可以被全局访问。这通常通过私有化构造函数、提供一个静态方法来获取实例的方式实现。

  1. 唯一性:保证一个类在系统中只有一个实例。
  2. 控制访问:提供一个全局访问点来获取该实例。
  3. 延迟初始化(可选):实例化可以延迟到第一次使用时,以节省资源。
实现单例模式的关键要素:
  • 私有构造函数:防止外部通过new关键字创建新的实例。
  • 静态方法或属性:用于存储和返回唯一的实例。
  • 线程安全:如果应用是多线程的,则需要确保在并发环境下也能正确工作。

二、定义与结构

定义:单例模式确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

结构

  • 单例类:负责创建和管理唯一的实例。
  • 静态成员变量:用于保存唯一的实例引用。
  • 获取实例方法:通常是一个静态方法,用于返回唯一的实例。
  • 私有构造函数:防止外部通过构造函数创建多个实例。
角色
  • 单例类:包含私有构造函数、静态成员变量和获取实例的静态方法。

三、实现步骤及代码示例

以Java为例,单例模式的实现方式有多种,包括饿汉式、懒汉式、双重检查锁定(Double-Checked Locking)和静态内部类实现方式等。以下是几种常见实现的代码示例:

1、饿汉式

  • 特点:在类加载时就创建实例,没有延迟加载的效果,但避免了多线程的同步问题。
  • 优点:线程安全,执行效率高。
  • 缺点:可能导致内存浪费,因为实例在类加载时就已创建,即使未使用。
public class HungrySingleton implements Serializable {private static final long serialVersionUID = 1L;private static final HungrySingleton hungry = new HungrySingleton();private HungrySingleton() {// 防止反序列化时重新创建实例if (hungry != null) {throw new RuntimeException("请使用 HungrySingleton.getInstance() 方法获取一个单例实例");}}public static HungrySingleton getInstance() {return hungry;}// 其他方法...
}

2、懒汉式(线程不安全)

  • 特点:按需加载,节省资源,只有在确实需要的时候才会创建实例。但存在线程安全问题。

  • 优点:延迟加载,提高了程序启动的速度。

  • 缺点:在多线程环境下需要额外的同步机制来保证线程安全。

  • 线程不安全的懒汉式示例代码:

public class LazySingleton {private static LazySingleton lazyMan;public LazySingleton() {// 构造函数可以为空或包含初始化代码}public static LazySingleton getInstance() {if (lazyMan == null) {lazyMan = new LazySingleton();}return lazyMan;}// 其他方法...
}

上述代码在多线程环境下可能会出现多个实例,因此线程不安全。

注意:懒汉式(线程不安全)在多线程环境下可能会导致多个实例被创建,因此通常不推荐使用。

3、双重检查锁定(Double-Checked Locking)

线程安全的懒汉式示例代码(双重检查锁定):

public class LazySafe {private static volatile LazySafe instance = null;private LazySafe() {}public static LazySafe getInstance() {if (instance == null) {synchronized (LazySafe.class) {if (instance == null) {instance = new LazySafe();}}}return instance;}
}

使用volatile关键字确保在多线程环境中正确处理,双重检查锁定保证了线程安全和性能。

4、静态内部类实现方式

  • 特点:利用Java的类加载机制实现延迟加载,线程安全且高效。

  • 优点:实现简单,无需额外的同步机制。

  • 缺点:无法支持非静态单例需求。

  • 示例代码:

public class InnerClassSingleton {private InnerClassSingleton() {// 构造函数可以为空或包含初始化代码}private static class Holder {private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();}public static InnerClassSingleton getInstance() {return Holder.INSTANCE;}// 其他方法...
}

5、枚举单例

  • 特点:实现简单,线程安全,防止反射和序列化破坏。

  • 优点:最简洁的实现方式,由Java语言本身保证线程安全性。

  • 缺点:不支持延迟加载。

  • 示例代码:

public enum Singleton {INSTANCE;public void someMethod() {// 单例方法逻辑}
}

四、JavaScript中的单例模式实现

基本实现

class Singleton {constructor() {if (typeof Singleton.instance === 'object') {return Singleton.instance;}Singleton.instance = this;}static getInstance() {if (!this.instance) {new this();}return this.instance;}someBusinessLogic() {// ...业务逻辑...}
}// 使用示例
const instanceA = Singleton.getInstance();
const instanceB = Singleton.getInstance();console.log(instanceA === instanceB); // true

模块模式下的单例

在JavaScript中,模块本身就是一个天然的单例,因为每个模块只会被加载一次。因此,可以利用ES6模块来实现单例模式。

// singleton.js
const singleton = (() => {let privateState = {}; // 私有状态function somePrivateMethod() {// 私有方法}return {publicMethod: function() {// 公共方法somePrivateMethod();},getPrivateState: function() {return privateState;}};
})();export default singleton;// 在其他文件中导入并使用
import singleton from './singleton';singleton.publicMethod();
console.log(singleton.getPrivateState());

线程安全的单例(适用于Node.js)

当涉及到多线程环境时,如Node.js worker_threads,可能需要确保线程安全。

class ThreadSafeSingleton {constructor() {if (!ThreadSafeSingleton.instance) {ThreadSafeSingleton.instance = this;}return ThreadSafeSingleton.instance;}static getInstance() {if (!this.instance) {// 如果是在多线程环境中,这里应该加入锁机制// 例如使用Promise或其他同步机制来保证线程安全new this();}return this.instance;}someBusinessLogic() {// ...业务逻辑...}
}

使用立即执行函数表达式(IIFE)

这是一种经典的JavaScript单例实现方式,尤其是在不支持模块化的旧版本浏览器中。

const singleton = (function () {const privateState = {}; // 私有状态function privateMethod() {// 私有方法}return {publicMethod: function () {// 公共方法privateMethod();},getPrivateState: function () {return privateState;}};
})();

五、常见技术框架应用

在Spring框架中,单例模式也得到了广泛应用。Spring容器默认创建的Bean是单例的,即在整个Spring IoC容器中,一个Bean只会有一个实例。以下是Spring中配置单例Bean的示例:

<bean id="myBean" class="com.example.MyBean" singleton="true"/>

或者,在基于注解的配置中,可以通过@Component@Bean注解来定义Bean,并默认其为单例:

@Component
public class MyBean {// ...
}@Configuration
public class AppConfig {@Beanpublic MyBean myBean() {return new MyBean();}
}

六、应用场景

单例模式常用于以下场景:

  1. 日志记录器:在整个应用程序中,通常只需要一个日志记录器来记录日志信息。
  2. 配置管理器:应用程序的配置信息通常只需要一个实例来管理,以确保配置的一致性。
  3. 数据库连接池:为了有效地管理数据库连接,避免频繁地创建和销毁连接,通常使用单例模式来创建数据库连接池。
  4. 线程池:管理和复用线程,避免频繁地创建和销毁线程,提高系统性能。
  5. 全局计数器:在需要全局唯一的计数器时,可以使用单例模式。
  6. 购物车服务:在电子商务网站中,用户的购物车应当是唯一的。
  7. 窗口管理器:图形界面程序中,窗口管理器应确保只有一个实例来协调所有窗口的行为。

七、优缺点

优点

  1. 延迟加载:只有在需要时才创建实例,节省资源。
  2. 全局访问点:提供一个全局访问对象的方式,方便在不同模块和组件之间共享资源。
  3. 控制资源:在需要限制实例数量的场景下(如数据库连接池、日志系统),单例模式能够确保系统中只有一个实例在操作资源。

缺点

  1. 线程安全问题:在多线程环境下,需要额外的同步机制来确保线程安全,可能会影响性能。
  2. 单例类的职责单一:单例模式通常要求单例类只承担一个职责,否则可能会违背单一职责原则,导致代码难以维护。

综上所述,单例模式是一种非常有用的设计模式,在需要控制资源访问和避免频繁创建对象的场景中发挥着重要作用。然而,在使用时也需要注意其潜在的缺点,并根据具体场景选择合适的实现方式。
在这里插入图片描述

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

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

相关文章

您的公司需要小型语言模型

当专用模型超越通用模型时 “越大越好”——这个原则在人工智能领域根深蒂固。每个月都有更大的模型诞生&#xff0c;参数越来越多。各家公司甚至为此建设价值100亿美元的AI数据中心。但这是唯一的方向吗&#xff1f; 在NeurIPS 2024大会上&#xff0c;OpenAI联合创始人伊利亚…

uniapp-vue3(下)

关联链接&#xff1a;uniapp-vue3&#xff08;上&#xff09; 文章目录 七、咸虾米壁纸项目实战7.1.咸虾米壁纸项目概述7.2.项目初始化公共目录和设计稿尺寸测量工具7.3.banner海报swiper轮播器7.4.使用swiper的纵向轮播做公告区域7.5.每日推荐滑动scroll-view布局7.6.组件具名…

使用 Python 实现随机中点位移法生成逼真的裂隙面

使用 Python 实现随机中点位移法生成逼真的裂隙面 一、随机中点位移法简介 1. 什么是随机中点位移法&#xff1f;2. 应用领域 二、 Python 代码实现 1. 导入必要的库2. 函数定义&#xff1a;随机中点位移法核心逻辑3. 设置随机数种子4. 初始化二维裂隙面5. 初始化网格的四个顶点…

活动预告 | Microsoft Power Platform 在线技术公开课:实现业务流程自动化

课程介绍 参加“Microsoft Power Platform 在线技术公开课&#xff1a;实现业务流程自动化”活动&#xff0c;了解如何更高效地开展业务。参加我们举办的本次免费培训活动&#xff0c;了解如何借助 Microsoft AI Builder 和 Power Automate 优化工作流。结合使用这些工具可以帮…

LLM(十二)| DeepSeek-V3 技术报告深度解读——开源模型的巅峰之作

近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的发展突飞猛进&#xff0c;逐步缩小了与通用人工智能&#xff08;AGI&#xff09;的差距。DeepSeek-AI 团队最新发布的 DeepSeek-V3&#xff0c;作为一款强大的混合专家模型&#xff08;Mixture-of-Experts, MoE&a…

el-pagination 为什么只能展示 10 条数据(element-ui@2.15.13)

好的&#xff0c;我来帮你分析前端为什么只能展示 10 条数据&#xff0c;以及如何解决这个问题。 问题分析&#xff1a; pageSize 的值&#xff1a; 你的 el-pagination 组件中&#xff0c;pageSize 的值被设置为 10&#xff1a;<el-pagination:current-page"current…

TCP网络编程(一)—— 服务器端模式和客户端模式

这篇文章将会编写基本的服务器网络程序&#xff0c;主要讲解服务器端和客户端代码的原理&#xff0c;至于网络名词很具体的概念&#xff0c;例如什么是TCP协议&#xff0c;不会过多涉及。 首先介绍一下TCP网络编程的两种模式&#xff1a;服务器端和客户端模式&#xff1a; 首先…

在K8S中,如何部署kubesphere?

在Kubernetes集群中&#xff0c;对于一些基础能力较弱的群体来说K8S控制面板操作存在一定的难度&#xff0c;此时kubesphere可以有效的解决这类难题。以下是部署kubesphere的操作步骤&#xff1a; 操作部署&#xff1a; 1. 部署nfs共享存储目录 yum -y install nfs-server e…

树莓派之旅-第一天 系统的烧录和设置

自言自语&#xff1a; 在此记录一下树莓派的玩法。以后有钱了买点来玩啊草 系统的安装烧录 系统下载 树莓派官网&#xff1a;https://www.raspberrypi.com/ 首页点击SoftWare进入OS下载页面 这里是安装工具&#xff1a;安装工具负责将系统镜像安装到sd卡中 点击下载符合自己…

商用车自动驾驶,迎来大规模量产「临界点」?

商用车自动驾驶&#xff0c;正迎来新的行业拐点。 今年初&#xff0c;交通部公开发布AEB系统运营车辆标配征求意见稿&#xff0c;首次将法规限制条件全面放开&#xff0c;有望推动商用车AEB全面标配&#xff0c;为开放场景的商用车智能驾驶市场加了一把火。 另外&#xff0c;…

人工智能及深度学习的一些题目

1、一个含有2个隐藏层的多层感知机&#xff08;MLP&#xff09;&#xff0c;神经元个数都为20&#xff0c;输入和输出节点分别由8和5个节点&#xff0c;这个网络有多少权重值&#xff1f; 答&#xff1a;在MLP中&#xff0c;权重是连接神经元的参数&#xff0c;每个连接都有一…

Solon 加入 GitCode:助力国产 Java 应用开发新飞跃

在当今数字化快速发展的时代&#xff0c;Java 应用开发框架不断演进&#xff0c;开发者们始终在寻找更快、更小、更简单的解决方案。近期&#xff0c;Solon 正式加入 GitCode&#xff0c;为广大 Java 开发者带来全新的开发体验&#xff0c;尤其是在国产应用开发进程中&#xff…

VScode 只能运行c,运行不了c++的解决问题

原文链接&#xff1a;Vscode只能运行c&#xff0c;运行不了c的解决方法 VScode 只能运行c&#xff0c;运行不了c&#xff0c;怎么回事呢&#xff0c;解决问题&#xff1a; 在tasks.json中加上“"-lstdc"”&#xff0c; 这样之后 要重启VScode&#xff0c;点击链接…

SpringCloud系列教程:微服务的未来 (五)枚举处理器、JSON处理器、分页插件实现

在现代 Java 开发中&#xff0c;我们常常需要处理各种通用的功能和需求&#xff0c;诸如枚举的处理、JSON 数据处理&#xff0c;以及分页查询等。这些功能虽然看似简单&#xff0c;但在实际开发中往往涉及到许多细节和优化。为了提高开发效率、减少重复代码的编写&#xff0c;我…

游戏引擎学习第69天

回顾碰撞响应时我们停留的位置 从昨天的讨论开始&#xff0c;我们正准备处理碰撞响应的复杂性。具体来说&#xff0c;我们讨论的是&#xff0c;当两个实体在屏幕上发生碰撞时&#xff0c;如何回应这种情况。碰撞本身并不复杂&#xff0c;但要处理其后的反应和规则则更具挑战性…

MAC环境安装(卸载)软件

MAC环境安装&#xff08;卸载&#xff09;软件 jdknode安装node&#xff0c;并实现不同版本的切换背景 卸载node从node官网下载pkg安装的node卸载用 homebrew 安装的node如果你感觉删的不够干净&#xff0c;可以再细分删除验证删除结果 jdk 1.下载jdk 先去官网下载自己需要的版…

本地LLM部署--llama.cpp

–图源GitHub项目主页 概述 llama.cpp是以一个开源项目&#xff08;GitHub主页&#xff1a;llamma.cpp&#xff09;&#xff0c;也是本地化部署LLM模型的方式之一&#xff0c;除了自身能够作为工具直接运行模型文件&#xff0c;也能够被其他软件或框架进行调用进行集成。 其…

uniapp中使用ruoyiPlus中的加密使用(crypto-js)

package.json中添加 "crypto-js": "^4.2.0", "jsencrypt": "^3.3.2",但是vue2中使用 import CryptoJS from cryptojs; 这一步就会报错 参照 参照这里&#xff1a;vue2使用CryptoJS实现信息加解密 根目录下的js文档中新增一个AESwork.…

go项目使用gentool生成model的gen.go问题

Gen Tool 是一个没有依赖关系的二进制文件&#xff0c;可以用来从数据库生成结构。 使用方法&#xff1a; go install gorm.io/gen/tools/gentoollatest在项目根目录,执行连接的数据库中指定某几张表结构生成数据库model层 gentool -dsn "root:123456tcp(localhost:330…

路由基本配置实验

路由器用于实现不同类型网络之间的互联。 路由器转发ip分组的基础是路由表。 路由表中的路由项分为直连路由项、静态路由项和动态路由项。 通过配置路由器接口的ip地址和子网掩码自动生成直连路由项。 通过手工配置创建静态路由项。 热备份路由器协议允许将由多个路由器组…