当前位置: 首页 > article >正文

设计模式从入门到精通之(三)单例模式

单例模式:只留一份独特的存在

在现代软件设计中,有些对象是必须确保"独一无二"的,比如程序中的配置管理器、线程池、数据库连接等。如果允许这些对象被反复创建,不仅会浪费系统资源,还可能导致程序逻辑出错。今天我们要聊的单例模式,正是用来解决这些问题的。


1. 什么是单例模式?

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并且提供全局访问点来获取该实例。简单来说,单例模式就是全球通用的唯一代言人

在实际开发中,单例模式常用于:

  1. 配置管理:程序中的全局配置只需要一个实例。
  2. 资源共享:某些资源(如线程池、日志系统)必须全局共享。
  3. 控制实例数量:限制某些类的实例数量,避免资源浪费。

2. 用现实中的故事引出单例模式

想象你在一个学校任教。学校的公告栏是全校师生获取通知的唯一地方,所有的信息都必须通过公告栏发布。假如学校允许多个公告栏存在,那可能会导致混乱,比如不同公告栏上的信息不一致。

因此,学校必须确保公告栏唯一性,而且所有人都知道它的位置。这就是单例模式的思想:一个类只能有一个实例,而且这个实例对全局都是可见的。


3. 单例模式的代码实现

下面我们以公告栏为例,来实现单例模式。

3.1 饿汉式单例

饿汉式单例在类加载时就完成实例化,因此线程安全,但如果实例从未被使用,会浪费内存。

class BulletinBoard {
    // 1. 提前创建唯一实例
    private static final BulletinBoard instance = new BulletinBoard();

    // 2. 私有构造方法,防止外部实例化
    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

    // 3. 提供全局访问点
    public static BulletinBoard getInstance() {
        return instance;
    }

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}

public class Main {
    public static void main(String[] args) {
        BulletinBoard board = BulletinBoard.getInstance();
        board.postMessage("明天学校停电,请提前做好准备。");
    }
}

运行结果:

公告栏已初始化
公告:明天学校停电,请提前做好准备。
3.2 懒汉式单例

懒汉式单例在第一次调用时创建实例,节省资源,但必须考虑线程安全问题。

class BulletinBoard {
    // 1. 声明静态变量,但不初始化
    private static BulletinBoard instance;

    // 2. 私有构造方法
    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

    // 3. 提供线程安全的全局访问点
    public static synchronized BulletinBoard getInstance() {
        if (instance == null) {
            instance = new BulletinBoard();
        }
        return instance;
    }

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}
3.3 双重检查锁(推荐)

双重检查锁结合了饿汉式和懒汉式的优点,既保证了线程安全,又提升了性能。

class BulletinBoard {
    private static volatile BulletinBoard instance;

    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

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

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}

4. 单例模式的优缺点

优点:

  1. 全局唯一性:确保一个类只有一个实例,节省资源。
  2. 全局访问:为程序提供统一的访问点,方便管理。
  3. 延迟初始化(懒汉式):提升性能,减少启动时的资源开销。

缺点:

  1. 不易扩展:由于单例模式强制只有一个实例,难以被继承或修改。
  2. 多线程问题:懒汉式实现需要小心处理线程安全。
  3. 隐藏依赖:过度使用单例可能让代码之间的依赖关系不清晰,增加维护难度。

5. 总结

单例模式看似简单,却是软件设计中的一颗"小而美"的明珠。在需要确保全局唯一性的时候,单例模式是非常高效的解决方案。但它也不是万能的,滥用单例可能导致代码难以测试和维护。

下一篇专栏中,我们将介绍一种和工厂模式密切相关的模式:建造者模式,看看如何一步步优雅地构建复杂对象。


思考问题:
在双重检查锁的实现中,为什么instance需要用volatile关键字修饰?如果省略,会产生什么问题?欢迎在评论区讨论!


http://www.kler.cn/a/471451.html

相关文章:

  • QT c++ 按钮 样式 设置按下和松开的背景颜色
  • OpenCV 4.5至4.10版本更新概述
  • linux-27 发行版以及跟内核的关系
  • 7_TypeScript Number --[深入浅出 TypeScript 测试]
  • ERP,Enterprise Resource Planning(企业资源计划)
  • Arduino IDE刷微控制器并下载对应固件的原由
  • mindspore更新set_context()为set_device()
  • 复制粘贴到可见单元格,并且带有原格式-Excel易用宝
  • 无人机+Ai应用场景!
  • 【C++】线程启动、结束与创建线程写法
  • 标准库简介 - STL容器、算法简介
  • 快手短剧播放器uniapp如何引入与对接?
  • Python实战技巧:字典键删除与数据处理
  • Kafka优势剖析-无锁设计与多线程模型
  • git push报错:fatal: Authentication failed for ‘https://gitclone.com
  • 华为ensp-BGP路由引入
  • HTML - <script>,<noscript>
  • MySQL insert or update方式性能比较
  • javascript-闭包
  • 万能无线航模模拟器加密狗说明书
  • 25/1/7 算法笔记<强化学习> sac_learn代码拆解
  • 云安全博客阅读(二)
  • PHP语言的数据库编程
  • 调整Python+Pytest+Allure+Yaml+Pymysql框架中需要执行的用例顺序
  • 自定义字典转换器用于easyExcel 导入导出
  • npm-npm install时rollbackFailedOptional: verb npm-session ce210dc17dd264aa报错