您的位置:首页 > 移动开发 > Android开发

设计模式之单例模式的几种常见写法

2017-10-29 18:34 357 查看
单例模式:一个类确保在全局中只有一个实例存在。

有时候我们需要一个类只能有一个实例,否则可能出现数据不同步的情况;有时我们需要考虑到

性能的优化,当创建过多的对象,会消耗很多的资源,造成不必要的资源浪费,这时就可以考虑

使用单例。

那么怎么去实现以及确保一个类是单例的呢?

单例模式要注意一下几点

(1) 私有化(private)构造函数,使得客户端不能通过new的形式来创建单例类实例。

(2) 通过一个静态方法或者枚举返回单例类对象。

(3) 确保单例类对象在全局中只有一个实例,特别是在多线程环境中。

常见的单例模式创建方法

假设有这么一个类HttpHelper,用于网络请求的封装,我们要求该类为单例模式。我们的写法可以如下:

(1) 饿汉单例模式,声明静态对象时就初始化

public class HttpHelper {
//注意这里有 final 修饰
private static final HttpHelper mHttpHelper = new HttpHelper();

//私有化构造函数
private HttpHelper() {
}

//公有的,对外暴露获取单例的方法
public static HttpHelper getHttpHelper() {
return mHttpHelper;
}
}

(2) 懒汉单例模式,先声明一个静态对象,当用户第一次调用时初始化

public class HttpHelper {
private static HttpHelper instance;

//私有化构造函数
private HttpHelper() {
}

//公有的,对外暴露获取单例的方法
public static HttpHelper getInstance() {
if (instance == null) {
instance = new HttpHelper();
}
return instance;
}
}

(3) 双重检查锁模式(Double Check Lock,DCL)

这种方式是既能够在需要的时候才初始化单例,又能够保证线程安全,且单例对象

初始化后再调用getInstance 不进行同步锁。看实例代码

public class HttpHelper {
private static HttpHelper instance;

//私有化构造函数
private HttpHelper() {
}

//公有的,对外暴露获取单例的方法
public static HttpHelper getInstance() {
if (instance == null) {
synchronized (HttpHelper.class) {
if (instance == null) {
instance = new HttpHelper();
}
}
}
return instance;
}
}

我基本都是用这种模式的单例。

(4) 静态内部类单例

DCL 在某些情况下会失效,因此有人建议使用以下这种方式。

public class HttpHelper {
//私有化构造函数
private HttpHelper() {
}

//公有的,对外暴露获取单例的方法
public static HttpHelper getInstance() {
return HttpHelperHolder.sInstance;
}

//静态内部类
private static class HttpHelperHolder{
private static final HttpHelper sInstance = new HttpHelper();
}
}

静态内部类的优势:当第一次加载HttpHelper类时并不会初始化sInstance,只有在第一次调用
getInstance()方法时才会初始化sInstance。也就是说在调用第一次调用getInstance()方法的
时候,才会去加载内部类HttpHelperHolder,这保证了线程安全,也能保证单例对象的唯一性,同
时延迟了单例的实例化,况且写法也不必其他方式复杂。所以可以考虑这种方式。

(5) 枚举单例

public enum HttpHelper {
INSTANCE;
}

这个是最简单的,而且可以避免在反序列化的情况下重新创建对象的情况。在jdk5.0才出现的枚举,现
在很多人都建议用这种方式来创建单例。很显然写法简单是他的优点。

以上几种方式是用得最多的单例模式写法。


总结下单例模式的优缺点:

(1) 单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例

模式的优势就很明显。

(2) 单例模式在全局只生成一个实例,减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、生产其他依赖对象时,则

可以通过在应用启动时直接生成一个单例对象,然后用永久驻留内存的方式来解决。

(3) 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免了对同一个资源的同时写操作。

(4) 单例模式可以在系统设置全局的访问点,优化和共享资源访问。

缺点:

(1) 单例模式没有接口,想要扩展只有修改代码这一条路。

(2) 单例对象如果持有Context,很容易引发内存泄漏,因此,我们传给单例对象的Context最好是Application Context。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息