年底了,手上的活不是很多,就想着将平时记录的笔记总结一下。准备总结一下平时常常使用的设计模式。本篇就是比较常用的单例(Singleton)模式。
不管是Android开发还是Java开发,相信单例模式都是用的比较多的,平时再用的时候有没有想过,到底有多少种写法,或者有么有什么坑没有踩呢?带着这些问题我们先来了解一下什么情况下会用到单例模式。
一般在希望系统中特定类只存在一个实例时,就可以使用单例模式。也就是说使用单例模式,最关心的是对象创建的次数,以及对象创建的时机。它的UML图也是非常的简单:
结构很简单,但是我们再使用时,还是想要有一些要求的:
1.在调用getInstance()方法时返回一个且唯一的Singleton对象。
2.能够在多线程使用时也能保证获取的Singleton对象唯一
3.getInstance()方法的性能要保证
4.能在需要的时候才初始化,否则不用初始化
现在就来按照上边的要求来实现吧。
写法一 饿汉式
/**
* 饿汉式
* 基于ClassLoader的机制,在同一classLoader下,该方式可以解决多线程同步的问题,
* 但是该种单例模式没有办法实现懒加载
*/
public class SingletonHungry {
/**
* 在ClassLoader加载该类时,就会初始化mInstance
*/
private static SingletonHungry mInstance = new SingletonHungry();
private SingletonHungry() {
}
public static SingletonHungry getInstance() {
return mInstance;
}
}
以上就是饿汉式的写法,满足了上边说的第1,2条要求。该模式有几点要注意:
1.默认构造方法需要私有化,不然外部可以随时的构造方法,这样就没法保证单例了。
2.SingletonHungry 类型的静态变量mInstance也是私有化的。这样外部就不能直接获取到mInstance,并且正是由于mInstance是静态变量并且声明时就初始化了,我们知道根据java虚拟机和ClassLoader的特性,一个类在一个ClassLoader中只会被加载一次。并且这里的mInstance在加载时就已经初始化了,这可以确定对象的唯一性。也就是说保证了在多线程并发情况下获取到的对象是唯一的。
当然该种方式肯定也是有缺点的,就是不能满足上边要求中的第三点,例如某类实例需求依赖在运行时的参数来生成,那么由于饿汉式在类加载时就已经初始化了,所以无法满足懒加载。那我们就来看看懒加载的写法。
* 写法二 懒加载(非线程安全)*
/**
* 懒汉式
* 只有在getInstance()时才会初始化mInstance
* Created by chuck on 17/1/18.
*/
public