详细讲解什么是单例模式

简介: 详细讲解什么是单例模式



概要


       当谈到单例模式时,我们指的是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式在软件开发中很常见,特别是需要控制资源访问、配置管理、日志记录器等情况下。

让我们用一个简单的例子来解释单例模式:

懒汉式


       假设有一个名为 Logger 的日志记录器类,我们希望确保系统中只有一个日志记录器实例,以便在整个应用程序中记录日志。

public class Logger {
    // 声明一个私有静态变量来保存单例实例
    private static Logger instance;
    // 私有构造函数,防止外部直接实例化该类
    private Logger() {
        // 这里可以进行初始化操作
    }
    // 公共静态方法来获取单例实例
    public static Logger getInstance() {
        // 如果实例不存在,则创建一个新实例
        if (instance == null) {
            instance = new Logger();
        }
        // 返回单例实例
        return instance;
    }
    public void log(String message) {
        // 记录日志的具体逻辑
        System.out.println(message);
    }
}

现在,让我们来理解上述代码:

  1. 私有静态变量 instance 这是用来保存单例实例的变量。它被声明为私有,因此其他类无法直接访问它。
  2. 私有构造函数: 构造函数被声明为私有,这意味着其他类无法通过 new 关键字直接实例化 Logger 类。
  3. getInstance() 方法: 这是获取 Logger 实例的静态方法。它首先检查实例是否已经存在,如果不存在,则创建一个新的实例并将其返回。如果实例已经存在,则直接返回现有的实例。

使用单例模式的示例代码如下:

public class Main {
    public static void main(String[] args) {
        // 获取 Logger 实例
        Logger logger1 = Logger.getInstance();
        Logger logger2 = Logger.getInstance();
        // 验证 logger1 和 logger2 是否是同一个实例
        System.out.println(logger1 == logger2); // 这里应该打印 true
        // 使用日志记录器记录信息
        logger1.log("This is a log message.");
        logger2.log("Another log message.");
    }
}

       在这个例子中,Logger 类只有一个实例,并且通过 getInstance() 方法进行访问。当我们尝试使用两个不同的变量 logger1logger2 获取实例时,实际上它们都引用了相同的实例,因此打印结果为 true。这确保了系统中只有一个 Logger 实例,并且任何地方使用日志记录器都在操作同一个实例。

饿汉式


       实际上,上面的例子展示的是最基本的单例模式,它是一种简单的懒汉式实现。懒汉式指的是在首次被调用时才创建实例。在这个例子中,当调用 getInstance() 方法时,会检查实例是否已经存在,如果不存在则创建一个新实例,否则返回现有实例。

       另一种常见的单例模式是饿汉式单例模式。饿汉式指的是在类加载时就创建实例,而不是在首次被调用时才创建。让我们来看一下饿汉式单例模式:

public class EagerSingleton {
    // 在类加载时就创建实例并进行初始化
    private static final EagerSingleton instance = new EagerSingleton();
    // 私有构造函数,防止外部直接实例化该类
    private EagerSingleton() {
        // 这里可以进行初始化操作
    }
    // 公共静态方法来获取单例实例
    public static EagerSingleton getInstance() {
        return instance;
    }
    public void someBusinessLogic() {
        // 进行一些业务逻辑操作
    }
}

在这个例子中:

  1. EagerSingleton 类有一个私有的、静态的、最终的实例变量 instance,它在类加载时就被创建和初始化。
  2. 构造函数被声明为私有,确保外部无法直接实例化该类。
  3. getInstance() 方法简单地返回预先创建的实例。

       饿汉式单例模式的优点是实现简单,并且在多线程环境下能够保持线程安全,因为实例在类加载时就已经创建。但缺点是如果该实例在整个程序运行期间未被使用,会造成资源浪费,因为它在类加载时就被创建了。

总结

       懒汉式和饿汉式单例模式各有其适用的场景。懒汉式可以延迟实例化,只有在需要时才创建,而饿汉式则在程序启动时就创建,适用于实例始终需要被使用的情况。

       单例模式可以帮助我们确保全局只有一个特定类的实例存在,这对于需要共享相同资源或状态的情况非常有用。但需要注意,如果不恰当地使用单例模式,可能会导致全局状态的滥用和应用程序结构的混乱。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
Java 关系型数据库 MySQL
高校宿舍报修管理系统的设计与实现(论文+源码)_kaic
高校宿舍报修管理系统的设计与实现(论文+源码)_kaic
|
SQL 存储 分布式计算
阿里巴巴瓴羊基于 Flink 实时计算的优化和实践
本⽂整理⾃阿里云智能集团技术专家王柳焮⽼师在 Flink Forward Asia 2023 中平台建设专场的分享。
1084 2
阿里巴巴瓴羊基于 Flink 实时计算的优化和实践
|
存储 关系型数据库 MySQL
如何在MySQL现有表中添加自增ID?
如何在MySQL现有表中添加自增ID?
1057 5
如何在MySQL现有表中添加自增ID?
|
机器学习/深度学习 自然语言处理 算法
跨模态学习能力再升级,EasyNLP电商文图检索效果刷新SOTA
本⽂简要介绍我们在电商下对CLIP模型的优化,以及上述模型在公开数据集上的评测结果。最后,我们介绍如何在EasyNLP框架中调用上述电商CLIP模型。
|
Cloud Native 关系型数据库 数据库
云原生之使用Docker部署Mariadb数据库
云原生之使用Docker部署Mariadb数据库
1174 1
云原生之使用Docker部署Mariadb数据库
|
9月前
|
监控 算法 API
用抖音电商 API 实现抖音小店商品标签精准打标
本文介绍如何利用抖音电商 API 实现商品标签精准打标,提升曝光与转化率。内容涵盖打标重要性、API 调用准备、标签自动化更新流程及最佳实践,助力商家高效运营,优化推荐效果。
594 0
|
监控 数据挖掘 数据安全/隐私保护
ERP系统中的成本核算与分析
【7月更文挑战第25天】 ERP系统中的成本核算与分析
1206 2
|
存储 芯片
51单片机--DS1302时钟
51单片机--DS1302时钟
473 0
|
机器学习/深度学习 传感器 编解码
LFM信号的回波与脉冲压缩附Matlab代码
LFM信号的回波与脉冲压缩附Matlab代码