一.定义
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
二、模式结构成员构成
单例模式包含如下角色:
• Singleton:单例
三.代码示例
/** * @author zhangboqing * @date 2018/2/26 * * 不好的解法一:只适用单线程环境 */ public class Singleton1 { private static Singleton1 instance = null; //私有构造 private Singleton1() { } public static Singleton1 getInstance() { if (Objects.isNull(instance)) { instance = new Singleton1(); } return instance; } } /** * @author zhangboqing * @date 2018/2/26 * * 不好的解法二:虽然在多线程环境中能工作,但是效率不高 */ public class Singleton2 { private static Singleton2 instance = null; //私有构造 private Singleton2() { } public static Singleton2 getInstance() { //同步代码块 synchronized (Singleton2.class){ if (Objects.isNull(instance)) { instance = new Singleton2(); } } return instance; } } /** * @author zhangboqing * @date 2018/2/26 * <p> * 可行的解法:加同步锁前后两次判断实例是否存在 */ public class Singleton3 { private static Singleton3 instance = null; //私有构造 private Singleton3() { } public static Singleton3 getInstance() { //第一次判断 if (Objects.isNull(instance)) { //同步代码块 synchronized (Singleton3.class) { //第二次判断 if (Objects.isNull(instance)) { instance = new Singleton3(); } } } return instance; } } /** * @author zhangboqing * @date 2018/2/26 * <p> * 强烈推荐的解法一:利用静态构造函数 */ public class Singleton4 { private static Singleton4 instance = new Singleton4(); //私有构造 private Singleton4() { } public static Singleton4 getInstance() { return instance; } } /** * @author zhangboqing * @date 2018/2/26 * <p> * 强烈推荐的解法二:实现按需创建实例 */ public class Singleton5 { //私有构造 private Singleton5() { } public static Singleton5 getInstance() { return Nested.instance; } //内部类 private static class Nested { private static Singleton5 instance = new Singleton5(); private Nested() { } } }
四.优点和缺点分析
优点:
>提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
>由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
>允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
缺点:
>由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
>单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
五.应用场景
在以下情况下可以使用单例模式:
>系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。