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

来源:互联网 发布:网络优化工程师考试 编辑:程序博客网 时间:2024/05/16 06:27
  1. 单例模式:一个类确保在全局中只有一个实例存在。
    有时候我们需要一个类只能有一个实例,否则可能出现数据不同步的情况;有时我们需要考虑到
    性能的优化,当创建过多的对象,会消耗很多的资源,造成不必要的资源浪费,这时就可以考虑
    使用单例。
  2. 那么怎么去实现以及确保一个类是单例的呢?
    单例模式要注意一下几点

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

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

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

  1. 常见的单例模式创建方法
    假设有这么一个类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. 总结下单例模式的优缺点:

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

模式的优势就很明显。

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

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

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

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

缺点:

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

(2) 单例对象如果持有Context,很容易引发内存泄漏,因此,我们传给单例对象的Context最好是Application Context。

原创粉丝点击