单例模式【Singleton Pattern】结构?特点?应用场景?优点与缺点?单例模式实现?

目录


设计模式专栏目录(点击进入…)



单例模式(Singleton Pattern) 是这些设计模式中的一种,它提供了一种创建对象的最佳方式,确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这种模式在需要严格控制资源访问、管理全局状态或实现共享资源访问时非常有用。

核心思想

单例模式的核心思想是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。它通过私有化构造函数和拷贝构造函数(以及赋值操作符,如果适用),并提供一个静态方法来创建和返回类的唯一实例,来实现这一目标。


单例模式结构

私有静态成员变量:用于存储类的唯一实例。
私有构造函数:防止外部代码通过new关键字直接创建类的实例。
私有拷贝构造函数和赋值操作符(如果适用):防止通过拷贝来创建新的实例。
公有静态方法:提供一个全局访问点来获取类的唯一实例。该方法在实例不存在时创建实例,如果实例已存在则直接返回该实例。


单例模式的特点

全局访问:可以通过一个全局访问点来获取类的唯一实例。
严格控制实例数量:确保类只有一个实例,并提供对该实例的全局访问。
懒汉模式与饿汉模式:单例模式的实现可以分为懒汉式和饿汉式,主要区别在于实例的创建时机。


单例模式应用场景

(1)当类需要控制自己的实例化,确保只有一个实例存在时。
(2)当全局访问点需要被多个类共享时,如配置文件的读取器、数据库连接池等。
(3)当资源访问需要被严格控制时,如打印机、线程池等。


单例模式的优点与缺点

优点

(1)控制资源访问

确保全局只有一个实例,从而可以严格控制对资源的访问。

(2)减少内存开销

避免了频繁创建和销毁实例所带来的性能开销。

(3)简化配置

在单例模式下,全局只有一个配置点,便于管理和维护。

(4)便于共享数据

单例模式提供了全局访问点,使得多个类可以方便地共享数据。

缺点

(1)扩展性差

单例模式对类的扩展性有一定影响,因为它限制了类的实例化方式。

(2)测试困难

在单元测试中,由于单例模式的全局唯一性,可能会导致测试之间的相互影响,增加测试难度。

(3)滥用可能导致问题

如果过度使用单例模式,可能会导致系统结构变得复杂,增加理解和维护的难度。

(4)多线程环境下需要特别注意线程安全

懒汉式单例模式在多线程环境下需要加锁来保证线程安全,这可能会引入性能问题。


单例模式实现

在这里插入图片描述

1、先定一个皇帝

懒汉模式

package com.uhhe.common.design.singleton;

/**
 * 中国的历史上一般都是一个朝代一个皇帝,有两个皇帝的话,必然要PK出一个皇帝出来【懒汉模式】
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 9:52
 */
public class Emperor {

    /**
     * 定义一个皇帝放在那里,然后给这个皇帝名字【懒汉模式】
     */
    private static Emperor emperor;

    private Emperor() {
        // 世俗和道德约束你,目的就是不让你产生第二个皇帝
    }

    /**
     * 提供全局访问点
     */
    public static Emperor getInstance() {
        // 如果皇帝还没有定义,那就定一个
        if (emperor == null) {
            // 加锁,哪个资源被共享,就加哪个
            synchronized (Emperor.class) {
                // 双重判断
                if (emperor == null) {
                    emperor = new Emperor();
                }
            }
        }
        return emperor;
    }

    /**
     * 皇帝叫什么名字呀
     */
    public void emperorInfo() {
        System.out.println("我就是皇帝某某某....");
    }

}

饿汉模式

package com.uhhe.common.design.singleton;

/**
 * 通用单例模式【饿汉模式】
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 10:03
 */
@SuppressWarnings("all")
public class SingletonPattern {

    private static final SingletonPattern SINGLETON_PATTERN = new SingletonPattern();

    /**
     * 限制住不能直接产生一个实例
     */
    private SingletonPattern() {
    }

    public synchronized static SingletonPattern getInstance() {
        return SINGLETON_PATTERN;
    }

}

2、定义大臣

package com.uhhe.common.design.singleton;

/**
 * 大臣是天天要面见皇帝,今天见的皇帝和昨天的,前天不一样那就出问题了!
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/2/27 9:56
 */
public class Minister {

    /**
     * 单例模式【Singleton Pattern】
     *
     * 大臣天天见到的都是同一个皇帝,不会产生错乱情况,反正都是一个皇帝,是好是坏就这一个
     * 只要提到皇帝,大家都知道指的是谁,清晰,而又明确。问题是这是通常情况
     * 还有个例的,如同一个时期同一个朝代有两个皇帝,怎么办?
     *
     * 单例模式很简单,就是在构造函数中多了加一个构造函数,访问权限是 private 的就可以了,这个模
     * 式是简单,但是简单中透着风险,风险?什么风险?在一个 B/S 项目中,每个 HTTP Request 请求到 J2EE
     * 的容器上后都创建了一个线程,每个线程都要创建同一个单例对象,怎么办?
     * 写一个通用的单例程序, 分析一下:
     */
    public static void main(String[] args) {
        Emperor emperor;

        //第一天
        emperor = Emperor.getInstance();
        //第一天见的皇帝叫什么名字呢?
        emperor.emperorInfo();

        //第二天
        emperor = Emperor.getInstance();
        emperor.emperorInfo();

        //第三天
        emperor = Emperor.getInstance();
        emperor.emperorInfo();

        //三天见的皇帝都是同一个人,荣幸吧!
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值