1.1 单例模式介绍
单例模式是我们最常用的一种模式之一 , 当然对于初级的工程师可能是唯一会使用的设计模式 , 最近越来越发现设计模式是多么的重要 , 所以最近就专攻 <<设计模式>> 这个大山 , 首先我们先从最简单的来开始吧 !
1.2 单例模式的定义
Ensure a class has only one instance, and provide a global point of access to it.
(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
1.2.1单例模式的缺点
单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。单例模式为什么不能增加接口呢?
因为接口对单例模式是没有任何意义的,它要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。
当然,在特殊情况下,单例模式可以实现接口、被继承等,需要在系统开发中根据环境判断。
单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行
测试的,没有接口也不能使用mock的方式虚拟一个对象。
单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境, 单例模式把 “要单例”和业务逻辑融合在一个类中。
1.2.2单例模式的使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”,可以采用单例模式,具体的场景如下:
● 要求生成唯一序列号的环境;
● 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
● 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
● 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当
然,也可以直接声明为static的方式)。
1.3 单例模式关键点
(1) 构建函数权限不对外开放 , 一般为Private
(2) 通过公共静态方法返回单例对象
(3) 确保只有一个实例 , 尤其是在多线程下
1.4 单例模式代码示例
单例模式一般分为两个模式: (1) 饿汉式 (2) 懒汉式
1.4.1 懒汉式
私有化构造函数和实例初始化,对外界提供一个静态方法判空并提供实例对象,保证只有一个实例
package com.example.liangshaoteng.imageloader;
/**
* Created by liangshaoteng on 17-6-26.
*/
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
1.4.2 饿汉式
实例化一个私有的实例对象通过静态方法返回给使用者,保证只有一个实例
package com.example.liangshaoteng.imageloader;
/**
* Created by liangshaoteng on 17-6-26.
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return singleton;
}
}
1.5 单例模式的其他实现方式
1.5.1 懒汉式
下面这个大家会发现多出一个synchronized方法这个就是我们之前说的确保一个实例尤其实在多线程下,我们可以通过synchronized方法进行同步,来保证唯一实例对象
package com.example.liangshaoteng.imageloader;
/**
* Created by liangshaoteng on 17-6-26.
*/
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
1.5.2 Double Check Lock (DCL)实现实例
大家在看的过程中会发现有两个判空,为什么呢? 这是因为如果我们不加第一个判断的话每使用一次都将进行同步,这样会消耗不必要的资源 , 这也是懒汉式存在最大的问题
package com.example.liangshaoteng.imageloader;
/**
* Created by liangshaoteng on 17-6-26.
*/
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
1.5.3 静态内部类单例实现
下面这个当我们加载Singleton的时候并不会实例化,只有在调用getInstance方法才会导致single被初始化
package com.example.liangshaoteng.imageloader;
/**
* Created by liangshaoteng on 17-6-26.
*/
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingleHolder.single;
}
private static class SingleHolder {
private static final Singleton single = new Singleton();
}
}
1.5.4 枚举
package com.example.liangshaoteng.imageloader;
import static com.example.liangshaoteng.imageloader.single.SINGLE;
/**
* Created by liangshaoteng on 17-6-26.
*/
enum single{
SINGLE;
public void doSomething(){
}
}