设计模式之单例模式

371 阅读4分钟

先说说为什么要开始学习设计模式

工作已经一年之久,很多时间心思大多都花在需求的完成上,需求的完成度很高,但是设计呢?

有没有考虑过你所实现的代码是否有设计在其中呢?

如果没有的话接下来和我一起学习设计模式哈~(不一定学习了设计模式就能提高你的设计,但是总归会有帮助)

什么是设计模式

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

设计模式的分类

按目的分类:

  • 创建型:主要用于创建对象。
  • 结构型:主要用于处理类或对象的组合。
  • 行为型:主要用于描述对类或对象怎样交互和怎样分配职责。

按范围分类:(模式主要是用于处理类之间关系还是处理对象之间的关系)

  • 类模型:处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是属于静态的。
  • 对象模型:处理对象间的关系,这些关系在运行时刻变化,更具动态性。

大概介绍了一些知识点,接下里我们进入设计模式的学习--单例模式

单例模式的定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 单例模式是一种对象创建型模式。

从他的定义我们可以看到有三个特点:

  • 实例唯一
  • 自行创建
  • 全局访问

让我们看看单例模式的类图是什么样子

我们可以看到:一个私有的当前类型的成员变量,一个私有的构造方法,一个 getInstance 方法。

创建对象不再通过new 而通过 getInstance 让该类自行创建。

接下来就是单例模式的实现啦

给大家介绍几种可用的单例模式的实现:

一 饿汉式(静态常量)

/**
 * 饿汉式(静态常量)
 */
class Singleton {
    private static final Singleton Instance = new Singleton();

    static Singleton getInstance() {
        return Instance;
    }

    private Singleton() {
    }
}

优点:简单,使用时没有延迟;在类装载时就完成实例化,天生的线程安全

缺点:没有懒加载,启动较慢;如果从始至终都没使用过这个实例,则会造成内存的浪费。

二 饿汉式(静态代码块)

/**
 * 饿汉式(静态代码块)
 */
class Singleton {
    private static Singleton Instance;

    static {
        Instance = new Singleton();
    }

    private Singleton() {
    }

    public static Singleton getInstance() {
        return Instance;
    }
}

这种是将类实例化的过程放在了静态代码块中,在类装载的时执行静态代码块中的代码,初始化类的实例。

优缺点同上。

三、双重检查(DCL)

/**
 * 双重检查(DCL)
 */
public class Singleton {

    private static volatile Singleton Instance;

    private King() {
    }

    public static Singleton getKingInstance() {
        if (Instance == null) {
            synchronized (Singleton.class) {
                if (Instance == null){
                    Instance = new Singleton();
                }
            }
        }
        return Instance;
    }
}

优点:线程安全;延迟加载;效率较高。

缺点:JDK < 1.5 的时候不可用

现在大家基本都是jdk1.8,所以也不存在这个问题。那为什么不可用呢?大家可以学习一下哈

使用场景

我们学习了怎么实现,那什么时候我们需要采用单例模式呢?

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。比如:

  • 需要频繁实例化然后销毁的对象
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象
  • 有状态的工具类对象
  • 频繁访问数据库或文件的对象

给大家介绍下具体的使用场景:

  • 比如网站的计数器,一般也是采用单例模式实现,否则难以同步
  • 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。主要是节省打开或者关闭数据库连接所引起的效率损耗
  • ...

这是几个比较常用的,大家可以参考这些想一下在自己的项目中是否采用了单例模式呢?又或者哪里也可以使用单例模式呢?

概述

其实单例模式的实现还有其他的实现方式,比如线程安全等等的,但是根据各方面,效率等因素,不推荐使用。

所以我在这里就只总结几个推荐大家使用的单例模式的实现。希望对大家有用。