设计模式之单例模式(静态属性可称为单例思想的特殊运用?)

本文介绍了设计模式中的单例模式,确保一个类只有一个实例并提供全局访问点。文章讨论了单例模式的定义、使用场景,如限制窗口数量,以及静态属性在其中的特殊应用。接着,通过Java代码展示了单例模式的两种实现方式——饿汉式和懒汉式,分别分析了它们的优缺点。最后,总结了单例模式的核心思想及其在GUI窗口和静态属性中的体现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  最近看了看程杰前辈的《大话设计模式》,主要是上次面试被问设计模式,答的很菜。。。经过一段时间的沉淀,现在来谈谈我对其单例模式的理解。

一、单例模式

1、定义

  单例模式(Singleton),保证一个类仅有一个实例,并且提供全局访问该实例的接口。简单的说,既要保证该类只有一个实例,也要保证全局访问的就是这个唯一的实例

2、使用场景

  那么肯定有小伙伴会问,单例模式有啥使用场景吗?限制一个类只有一个实例,这种场景比较少吧。。。
  确实,限制一个类只有一个实例的场景比较少,但是并不代表单例模式毫无用武之地。举个栗子,运用程序是如何维持某个窗口只一个的?比如系统桌面右键菜单。
在这里插入图片描述
  如果不控制窗口对应的对象同一时刻只有一个,那么可能你每点一次,都会弹出一个同样的窗口。这显然不符合实际逻辑,也会造成资源的浪费。

  其实还有另外一种普遍的场景,类中的静态属性。我想写过面向对象编程序思想的程序小伙伴都在类中定义过static属性,我们把某个变量加上static关键字修饰,目的是把这个变量声明为本身所有,而不是类的实例所有。最主要的作用不就是类的所有实例都来访问这同一个static属性,这正好与我们单例模式的思想吻合。

二、举例(静态属性)

  上面提到了 类中的静态属性是单例模式思想的一种特殊运用,下面我们通过代码来模拟一下。

public class SingleTon {
    // 对object属性添加static修饰(这个变量属于SingleTon类,不属于实例)
    public static MyClass object = new MyClass();

    public static void main(String[] args) {
        // 新建两个SingleTon对象
        SingleTon singleTonOne = new SingleTon();
        SingleTon singleTonTwo = new SingleTon();
        // 由于Java提供通过类实例访问类静态属性的途径,所以这里我们测试一下
        // 两个实例访问的是否为同一个实例object(这里只是演示,实际编写代码千万别通过对象访问类静态属性!!!)
        System.out.println(singleTonOne.object);
        System.out.println(singleTonTwo.object);
    }
}

class MyClass{
    public MyClass(){

    }
}

在这里插入图片描述
  由于在Java语言中,每个类只能加载一次,因此SingleTon类中的object属性只会被初始化一次,也就是只有一个。通过观察程序的输出,确实发现两个实例共用SingleTon类中的object静态属性,做到了只有一个实例。但这个程序不能称为严格的单例,因为在任何地方都可以通过调用MyClass类的构造器来手动创建MyClass的实例,因此这提示我们需要修改单例对应的类的构造器访问权限为私有(private关键字修饰)。在阅读下文前,可以思考一下如何改造这个程序,使MyClass变为严格的单例。

三、两种实现方式(Java)

  单例模式的实现,常见的方法有两种,分别是懒汉式饿汉式,两者都将类的构造器私有化,但是各有优缺点。

1、饿汉式

  将构造器私有化,并且用static属性初始化一个实例。这样每次就只能访问同一个实例,并且限制了类的new操作(构造器被私有化了)。

public class SingleTonTest {
    public static void main(String[] args) {
        // 通过SingleTon.getInstance接口,两次获取SingleTon类的实例
        SingleTon singleTonOne = SingleTon.getInstance();
        SingleTon singleTonTwo = SingleTon.getInstance();
        // 打印两次获取的实例的内存地址
        System.out.println(singleTonOne);
        System.out.println(singleTonTwo);
    }
}

class SingleTon{
    // SingleTon静态属性,初始化时new一个对象(类中能使用该类声明的private方法)
    private static SingleTon singleTon = new SingleTon();
    // 构造器私有了,外部不能new对象(保证了虚拟机中只能有一个实例)
    private SingleTon(){

    }
    // 对外展示访问SingleTon实例的接口(保证了全局访问的都是SingleTon类的同一个实例)
    public static SingleTon getInstance() {
        return singleTon;
    }
}

在这里插入图片描述
  该方式的特点就是在加载类的时候就new一个唯一的实例,以后直接通过相应的API获取,继而保证了实例唯一,并且全局访问同一个实例。提高了使用效率,但是可能出现资源浪费的情况,假设整个程序运行过程中都没访问这个实例,那不是白白生成了一个实例。。。

2、懒汉式

  同样将类的构造器私有化,但是对外展示的获取实例的API智能生成实例,如果已经生成过了实例,直接放回之前的示例,否则生成一个新的实例。

public class SingleTonTest {
    public static void main(String[] args) {
        // 通过SingleTon.getInstance接口,两次获取SingleTon类的实例
        SingleTon singleTonOne = SingleTon.getInstance();
        SingleTon singleTonTwo = SingleTon.getInstance();
        // 打印两次获取的实例的内存地址
        System.out.println(singleTonOne);
        System.out.println(singleTonTwo);
    }
}

class SingleTon{
    // SingleTon静态属性,指向生成的SingleTon实例
    private static SingleTon singleTon = null;
    // 构造器私有了,外部不能new对象(保证了虚拟机中只能有一个实例)
    private SingleTon(){

    }
    // 对外展示访问SingleTon实例的接口(保证了全局访问的都是SingleTon类的同一个实例)
    // 可能存在线程不安全的情况(多个线程同时调用getInstance,此时可能生成多个实例),使用synchronized关键字修饰,默认是SingleTon.class锁
    public static synchronized SingleTon getInstance() {
        if (singleTon == null) {
            // 为null就new一个实例
            singleTon = new SingleTon();
        }
        return singleTon;
    }
}

在这里插入图片描述

  懒汉式中的字,就是由 先判断是否生成过实例,再考虑是否生成实例而来。这种方式解决了饿汉式可能浪费资源的问题,但是降低了使用效率,因为每次都需要加锁、判断是否为null、释放锁。

四、总结

  单例模式是众多设计模式中较为简单的一种,核心思想是保证某类有且只用一个实例对象,并且需要保证全局都只能访问这个唯一的实例。
  经典的例子就是GUI中的窗口,同一个窗口类一般只能有一个对象。不过博主个人认为,类中的static属性是单例思想的一种特殊运用,因为它保证了在本类中所用的对象访问同一个static属性(大家看看就行,别当真😂😂😂)。
在这里插入图片描述

资料参考:
《大话设计模式》程杰著 单例模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值