Android设计模式——单例模式
来源:互联网 发布:小黄鸭淘客软件合法吗 编辑:程序博客网 时间:2024/06/08 02:57
单例模式
介绍
单例模式是应用最广的模式之一。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象。
定义
确保某一个类只有一个实例,而且自行实例化向整个系统提供这个实例。
使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。创建一个对象需要消耗的资源过多。就需要考虑使用单例模式
使用单例模式的关键点:
- 构造函数不对外开放,一般为private
- 通过一个静态方法或者枚举返回单例对象
- 确保单例类的对象有且只有一个
确保单例类的对象在反序列化时不会重新构建对象
- 解释:通过将单例类的构造函数私有化,使得客户端代码不能通过new的形式手动构造单例类的对象。单例类会暴露一个公有静态方法,客户端需要调用这个静态方法获取到单例类的唯一对象,在获取这个单例对象的过程中需要确保县城安全。即在多线程的环境下构造单例类的对象也是只有一个
实例:
模拟一个公司的员工情况,一个公司有多个员工Staff 有多个副总VP 但是只有一个CEO 无论在什么情况下,CEO总保持只有一个
- Staff模型
/** * Describe:员工模型 * wx on 2016/12/29. */public class Staff { public void work() { System.out.println("staff is do something"); }}
- VP模型
/** * Describe:VP模型 * wx on 2016/12/29. */public class VP extends Staff { @Override public void work() { System.out.println("vp manager staff"); }}
- CEO模型
/** * Describe:CEO模型 * wx on 2016/12/29. */public class CEO extends Staff { private static CEO ceo = new CEO(); /** * 私有构造方法 */ private CEO() { } /** * 静态提供实例方法 */ public static CEO getInstance() { return ceo; } @Override public void work() { System.out.println("ceo manager staff"); }}
- Company模型
/** * Describe:公司模型 * wx on 2016/12/29. */public class Company { private List<Staff> allStaffs = new ArrayList<Staff>(); public void addStaff(Staff staff) { allStaffs.add(staff); } public void showAllStatffs() { for (Staff allStaff : allStaffs) { System.out.println("obj" + allStaff.toString()); } }}
- Test
/** * Describe: * wx on 2016/12/29. */public class Test { public static void main(String[] args) { Company cp = new Company(); // TODO: 创建CEO对象 CEO ceo1 = CEO.getInstance(); CEO ceo2 = CEO.getInstance(); // TODO: 入职 cp.addStaff(ceo1); cp.addStaff(ceo2); // TODO: 创建VP Staff vp1 = new VP(); Staff vp2 = new VP(); // TODO: VP入职 cp.addStaff(vp1); cp.addStaff(vp2); Staff staff1 = new Staff(); Staff staff2 = new Staff(); Staff staff3 = new Staff(); // TODO: 员工入职 cp.addStaff(vp1); cp.addStaff(vp2); cp.addStaff(staff1); cp.addStaff(staff2); cp.addStaff(staff3); // TODO: 查看所有员工 cp.showAllStatffs(); }}
运行结果:
objcom.individual.wx.singlemode.singleton.CEO@7d4991adobjcom.individual.wx.singlemode.singleton.CEO@7d4991adobjcom.individual.wx.singlemode.singleton.VP@28d93b30objcom.individual.wx.singlemode.singleton.VP@1b6d3586objcom.individual.wx.singlemode.singleton.VP@28d93b30objcom.individual.wx.singlemode.singleton.VP@1b6d3586objcom.individual.wx.singlemode.singleton.Staff@4554617cobjcom.individual.wx.singlemode.singleton.Staff@74a14482objcom.individual.wx.singlemode.singleton.Staff@1540e19d
单例的几种实现方式
懒汉式
- 懒汉式是声明一个静态对象,并且在用户第一次调用getInstance时进行初始化,而饿汉式是在声明静态对象时就已经初始化。
- 懒汉式实现:
/** * Describe:懒汉式单例模式 * wx on 2016/12/29. */public class SingleTon { public static SingleTon instance; private SingleTon() { } public static synchronized SingleTon getInstance() { if (instance == null) { instance = new SingleTon(); } return instance; }}
- 存在问题:
懒汉式单例模式实现中,即使instance已经被初始化,调用getInstance还是会进行同步,这样会消耗不必要的资源。
Double Check Lock (DCL) 实现单例
- DCL实现单例模式的优点是既能在需要时才初始化单例,又能保证线程安全,且单例对象初始化后调用getInstance不进行同步锁
/** * Describe:Double Check Lock 实现单例模式 * wx on 2016/12/29. */public class DCLSingleTon { private static DCLSingleTon instance = null; private DCLSingleTon() { } public static DCLSingleTon getInstance() { // TODO: 第一次判空为了避免不必要的同步 if (instance == null) { synchronized (SingleTon.class) { // TODO: 第二次判空为了没有实例时创建实例对象 if (instance == null) { instance = new DCLSingleTon(); } } } return instance; }}
explain: 可见整个程序进行了两次非空判断,第一次的非空判断是为了避免不必要的同步,也就是说在instance为空的时候,也就是需要的时候才进行同步锁定。第二次非空判断,是为了实例并不存在的时候初始化。
DCL单例模式的有缺点
- 缺点:第一次加载的时候反应会稍微慢,也会由于java内存模型的原因偶尔会失败
- 优点:资源利用率高,在第一次执行getInstance()时单例对象才会被实例化,效率高
静态内部类实现单例模式
- DLC虽然在一定程度上解决了资源消耗、多余同步、线程安全等问题,但是,在某些情况下还是会出现失效的问题。这个问题被称为双重检查锁定失效,在《Java并发编程实践》中给出优化方案:
/** * Describe:静态内部类实现单例模式 * wx on 2016/12/29. */public class InnerSingleTon { private InnerSingleTon(){} public static InnerSingleTon getInstance(){ return InnerSingleTonHolder.sInstance; } private static class InnerSingleTonHolder { public static InnerSingleTon sInstance = new InnerSingleTon(); }}
- 第一次加载InnerSingle类时并不会初始化sInstance,只有在第一次调用getInstance()的时候才会导致sInstance被初始化。
反序列化的问题
通过序列化可以将一个单例的实例对象写到磁盘,然后再读回来,从而有效地获得一个实例,即使构造函数是私有的,反序列化时依然可以通过特殊的途径去创建类的一个新的实例,相当于用该类的构造函数,反序列化操作提供了一个很特别的钩子函数,类中具有一个私有的、被实例化方法readResolve(),这个方法可以让开发人员控制对象的反序列化。例如要杜绝单例对象在被反序列化时重新生成对象。那么必须加入如下方法:
private Object readResolve() throws ObjectStreamException{ return sInstance;}
枚举单例
使用枚举单例是好处是,写法简单,默认枚举实例的创建是线程安全的,并且在任何情况下它都是一个单例。枚举在反序列化时也不会重新生成新的实例
/** * Describe:枚举单例 * wx on 2016/12/29. */public enum EnumSingleTon { INSTANCE; public void doSomeThing(){ System.out.println("enm do sth."); }}
使用容器实现单例
/** * Describe:容器单例 * wx on 2016/12/29. */public class SingleTonManager { private static Map<String, Object> objMap = new HashMap<String, Object>(); private SingleTonManager() { } public static void regiserService(String key, Object instance) { if (!objMap.containsKey(key)) { objMap.put(key, instance); } } public static Object getService(String key) { return objMap.get(key); }}
- 在程序的开始,将许多单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式可以让我们管理多种类型的单例。并且在使用时可以通过统一的接口进行获取操作
Android源码中的单例模式
- 在Android系统,我们会经常会通过Context获取系统级别的服务,如WindowManagerService、ActivityManagerService等。更常用的是一个LayoutInflater的类。这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候就通过Context的getSystemService(String name)获取。
- 在Android系统中,还有类似于LayoutInflate也是在运行时先注册到系统服务器管理中,然后在使用时直接根据名字来进行使用的单例模式
- 由于水平比较菜,所以还不不贴源码了,但是在Android源码中,还是有很多单例的设计模式的使用地方的,一定要去看看啊
总结
虽然在客户端中没有太多的高并发的情况,因此单例模式的使用与否并不会有太大的影响。在使用单例模式时一定要注意由于系统中只存在一个对象,那么对于这个对象的赋值和操作会影响到整个系统的使用,在这点还是应该注意的。一般对于资源消耗大的类,方便程序的性能提升 还是比较推荐使用单例模式来进行对象的管理的。
优点:
1.由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建和销毁时,单例模式就非常明显了
2. 由于单例模式只生成一个实例,所以减少了系统性能的开销。当一个对象的产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个对象,然后永久驻留内存的方式来解决
3. 单例模式可以避免对资源的多重占用。
4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问。
缺点
1.单例模式一般没有接口,拓展比较困难
2.单例对象如果持有Context,那么很容易发生内存泄漏,需要注意传递给单例对象的Context最好是Application Context.
- Android 设计模式—单例模式
- Android 设计模式—单例模式
- 设计模式—单例设计模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android与设计模式——单例(Singleton)模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android开发设计模式之——单例模式
- Android设计模式——单例模式。
- Android开发设计模式之——单例模式
- Android设计模式——单例模式
- Android设计模式——单例模式
- Android设计模式(一)——单例模式
- Android开发设计模式之——单例模式
- xcode关于ARC的疑惑
- 后台使用国际化
- 使用 GROW 模型
- LayaAir引擎学习日志13----LayaAir怎么在mac环境下打包成ios的app以及发布的所有流程
- 基于C# Winform的串口数据接收
- Android设计模式——单例模式
- python 实现递归删除文件和文件夹
- Oracle sql loader 导数据时添加序号的三种方法
- 4 种方法识别Linux系统 USB 设备
- Xcode6 SizeClass疑问
- 几个属性修饰的问题retain 和 copy
- 调试STM32 time遇到的问题小结
- Hrbust 1638 新年快乐【对称博弈】
- 【解决方案】Ubuntu14.04 卸载ibus导致System Settings异常