意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

解决的问题

对一些类来说,只有一个实例是很重要的。一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求)​,并且它可以提供一个访问该实例的方法。这就是单例模式。

所以,在当我们需要控制某个类在全局中仅有一个实例的时候,就可以使用该模式。

例子介绍

  1. 对于一个班级来说,往往只需要一个班主任就可以管理好了,不需要创建过多的“班主任”对象来管理,从而造成资源浪费。

内部结构

Singleton.png

参与者及其协作过程

  1. Singleton

    • 定义一个Instance操作,允许客户访问它的唯一实例。

    • 可能负责创建它自己的唯一实例

已知示例

JAVA中的java.lang.Runtime对象,就是一个典型饿汉式单例对象,源码如下

public class Runtime {
    
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}

代码示例

饿汉式单例对象

/**
 * 饿汉单例对象
 */
public class SingletonObj {

    private static final SingletonObj singletonObj = new SingletonObj();

    /**
     * 使构造私有化,防止被外部创建
     */
    private SingletonObj() {
    }

    public static SingletonObj instance() {
        return singletonObj;
    }

    public void info() {
        System.out.println("这是一个饿汉单例对象");
    }
}

懒汉式单例对象

/**
 * 线程安全的懒汉单例
 */
public class SingletonObj1 {

    private SingletonObj1(){}

    private static SingletonObj1 singletonObj1 = null;

    public static synchronized SingletonObj1 instance(){
        if (singletonObj1 == null){
            singletonObj1 = new SingletonObj1();
        }
        return singletonObj1;
    }

    public void info(){
        System.out.println("这是一个线程安全的懒汉单例对象");
    }
}

测试用例

package cn.zhengzl.creation.singleton;

public class SingletonTest {

    public static void main(String[] args) {
        SingletonObj instance = SingletonObj.instance();
        instance.info();
        SingletonObj1 singletonObj1 = SingletonObj1.instance();
        singletonObj1.info();
    }
}

输出结果

这是一个饿汉单例对象
这是一个线程安全的懒汉单例对象

小结

优点

  1. 对唯一实例的受控访问

  2. 避免创建过多的实例对象,有效控制资源消耗

缺点

  1. 不利于扩展

  2. 单例类的职责过重,在一定程度上违背了“单一职责原则”