设计模式之单例模式的几种常见写法
2017-10-29 18:34
357 查看
单例模式:一个类确保在全局中只有一个实例存在。
有时候我们需要一个类只能有一个实例,否则可能出现数据不同步的情况;有时我们需要考虑到
性能的优化,当创建过多的对象,会消耗很多的资源,造成不必要的资源浪费,这时就可以考虑
使用单例。
那么怎么去实现以及确保一个类是单例的呢?
单例模式要注意一下几点
(1) 私有化(private)构造函数,使得客户端不能通过new的形式来创建单例类实例。
(2) 通过一个静态方法或者枚举返回单例类对象。
(3) 确保单例类对象在全局中只有一个实例,特别是在多线程环境中。
常见的单例模式创建方法
假设有这么一个类HttpHelper,用于网络请求的封装,我们要求该类为单例模式。我们的写法可以如下:
总结下单例模式的优缺点:
(1) 单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例
模式的优势就很明显。
(2) 单例模式在全局只生成一个实例,减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、生产其他依赖对象时,则
可以通过在应用启动时直接生成一个单例对象,然后用永久驻留内存的方式来解决。
(3) 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免了对同一个资源的同时写操作。
(4) 单例模式可以在系统设置全局的访问点,优化和共享资源访问。
缺点:
(1) 单例模式没有接口,想要扩展只有修改代码这一条路。
(2) 单例对象如果持有Context,很容易引发内存泄漏,因此,我们传给单例对象的Context最好是Application Context。
有时候我们需要一个类只能有一个实例,否则可能出现数据不同步的情况;有时我们需要考虑到
性能的优化,当创建过多的对象,会消耗很多的资源,造成不必要的资源浪费,这时就可以考虑
使用单例。
那么怎么去实现以及确保一个类是单例的呢?
单例模式要注意一下几点
(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。
相关文章推荐
- JAVA几种常见的设计模式
- 几种常见的设计模式
- 单列设计模式几种写法的比较
- JAVA几种常见的设计模式
- java之 ------ 几种常见的简单设计模式
- 对几种常见设计模式的理解
- C++几种常见设计模式的UML图
- java中几种常见的设计模式
- 设计模式:几种常见的设计模式
- 单例模式及常见写法分析(设计模式01)
- 几种常见的 PHP 设计模式(转)
- 面向对象编程的几种常见设计模式
- 几种常见的设计模式
- 列出几种软件开发中常见的设计模式并解释
- 单例模式及常见写法分析(设计模式01)
- 单例模式及常见写法分析(设计模式01)
- 几种常见算法设计模式
- C++中几种常见的单例模式写法。
- 常见的几种设计模式
- 几种常见设计模式(Java)