《java设计模式》一文带你了解单例模式

写在前面

五一放假了,大家是不是因为疫情都减少了出门的频率那?不出门我们就一起在家学习吧!下面就让我们从一个问题出发,开始今天的文章吧。你的类有没有“超生”(到处都是该类的实例)那,它是不是也需要“计划生育”(只需要一个实例)啊?什么你不会?没事让我来告诉你解决类“超生”的办法,使用单例设计模式。下面让我们来一起学习一下单例模式。

概述

什么是单例模式?

单例模式是创建类型中常用的一种设计模式。该模式下的类有且仅有一个实例。

优点

1、可以严格控制单例类的使用者怎样以及何时访问唯一的实例。
2、只有一个实例,可以节约系统资源,提高系统的性能,减轻GC的压力。

凡事有利就要弊,单例模式也不可以滥用。

缺点

1、单例模式的扩展性很差,因为没有抽象层。
2、单例模式在一定程度上违背了“单一职责原则”。

不可以将数据库连接池对象设计为的单例类,如果共享连接池对象的程序过多会出现连接池溢出的问题。不可以使用反射,这样会声明出另一个实例。

创建方式

1、饿汉式
提前创建好类的实例不需要等待创建的时间,直接就可以使用。

/**
 * 饿汉式(单例模式)
 */
public class HungrySingleton {

  // 私有构造方法
  private HungrySingleton() {
  }

  // 创建一个实例
  private static final HungrySingleton 
                HUNGRY_SINGLETON_INSTANCE = new HungrySingleton();

  /**
   * 获取实例的方法
   */
  public static HungrySingleton getHungrySingleton() {
    return HUNGRY_SINGLETON_INSTANCE;
  }
}
复制代码

该方式可能在还不需要此实例的时候就已经将创建出来了,没有起到懒加载的效果。

2、使用静态内部类
通过使用静态内部类的方式优化上面的饿汉式,起到懒加载的效果。

/**
 * 使用静态内部类完成单例模式
 */
public class HungrySingleton {

  // 私有构造方法
  private HungrySingleton() {
  }

  // 利用静态类的加载时机实现懒加载
  private static class InnerHungrySingleton{
    private static final HungrySingleton 
                    HUNGRY_SINGLETON_INSTANCE = new HungrySingleton();
  }

  /**
   * 获取实例的方法
   */
  public static HungrySingleton getHungrySingleton() {
    return InnerHungrySingleton.HUNGRY_SINGLETON_INSTANCE;
  }
}
复制代码

3、懒汉式
在第一次使用时创建实例,使用时需要考虑线程安全问题。

/**
 * 懒汉式(单例模式)
 */
public class LazySingleton {

  // 私有构造方法
  private LazySingleton() {
  }

  // 私有静态属性
  private static LazySingleton lazySingletonInstance;

  /**
   * 获取实例的方法
   */
  public static LazySingleton getLazySingleton() {
    // 双重判断
    if (null == lazySingletonInstance) {
      synchronized (LazySingleton.class) {
        if (null == lazySingletonInstance) {
          lazySingletonInstance = new LazySingleton();
        }
      }
    }
    return lazySingletonInstance;
  }
}
复制代码

该方式起到了懒加载的效果,并且也做了线程安全处理。

4、使用枚举
利用枚举的特性让JVM来保证线程安全问题和单一实例的问题。

/**
 * 使用枚举实现单例
 */
public enum SingletonEnum {
  INSTANCE;

  private People people;

  SingletonEnum(){
    people = new People();
  }

  public People getPeople() {
    return people;
  }

  // 定义了一个内部类,为了方便代码展示,也可以是一个独立的类。
  class People {
  }
}
复制代码

使用枚举有一个缺点是需要更多的内存空间。

今天的分享就到这里了,看在我五一放假还坚持分享的份上大家能不能给我点个赞啊?

猜你喜欢

转载自juejin.im/post/5eae3680f265da7bb56382b7