Android设计模式-单例模式

单例模式介绍

最近在学习设计模式,本篇博文主要是对《Android源码设计模式》一书中的知识点整理和总结,算是我自己的一个读书笔记。单例模式是应用最广的设计模式之一。在应用这个模式时,单例对象的类必须保证只有一个实例存在。

特点

单例模式有以下特点:
1. 单例类只能有一个实例;
2. 单例类自行实例化;
3. 单例类向整个系统提供这一实例。

使用场景:
确保某个类有且只有一个对象,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如:创建一个对象需要消耗的资源过多,如要访问IO和数据库资源。

优缺点

优点:
1. 只存在一个实例,减少了内存开支,特别是一个对象需要频繁新创建销毁时;
2. 减少系统性能开销,当一个对象的产生需要比较多的资源,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决
3. 可以避免对资源的多重占用,例如写文件操作,由于只有一个实例在内存中,避免对同一资源文件的同时写操作
4. 单例模式可以在系统设置全局的访问点,优化和共享资源,例如,设计一个单例类,负责所有数据表的映射处理。
缺点:
1. 一般没有接口,扩展比较困难,基本上只能修改代码
2. 单例对象如果只有context,很容易引发内存泄露最好使用ApplicationContext

单例模式的实现方式

单例模式的实现主要有以下几个关键点:
1. 构造函数不对外开放,通常为private,不能通过new的形式来构建对象
2. 通过一个静态方法或者枚举返回单例对象
3. 确保单例类的对象个有且只有一个,尤其是在多线程环境下,保证线程安全
4. 确保单例类对象在反序列化不会重新构建对象

饿汉模式

    //饿汉式单例类.在类初始化时,已经自行实例化   
    public class Singleton {  
        private Singleton() {}  
        private static final Singleton single = new Singleton();    
        public static Singleton getInstance() {  
            return single;  
        }  
    }

饿汉模式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的。但是饿汉模式在类创建时就实例化一个静态对象,不管之后会不会使用这个单例,都会占据一定的内存。

懒汉模式

    //懒汉式单例类.在第一次调用的时候实例化自己   
    public class Singleton {  
        private Singleton() {}  
        private static Singleton single=null;  

        public static synchronized  Singleton getInstance() {  
             if (single == null) {    
                 single = new Singleton();  
             }    
            return single;  
        }  
    }

懒汉模式是声明一个静态对象,并且在第一次调用getInstance时才会进行初始化,一定程度上节约了资源。但是第一次加载时需要进行实例化,反应稍慢。懒汉模式本身是非线程安全的,为了实现线程需要添加synchronized 关键字。每次调用getInstance都进行同步,造成不必要的同步开销。这种模式不推荐使用。

DCL(Double Check Lock)

    private static Singleton instance=null; 
    private Singleton() {}
    public static Singleton getInstance() {  
            if (instance == null) {    
                synchronized (Singleton.class) {    
                   if (instance == null) {    
                      instance = new Singleton();   
                   }    
                }    
            }    
            return singleton;   
        } 

DCL模式既能够在需要时才实例化单例,又能够保证线程安全,且单例对象在初始化后调用getInstance不进行同步。第一次加载时反应稍慢,在一些低版本JDK存在DCL失效问题。JDK1.5以后如果申明实例引用为volatile,可以解决DCL失效。
private volatile static Singleton instance=null;
是使用最多的单例实现方式。
在getInstance中对instance进行了两次判空:
第一次判断为了避免不必要的同步,第二层判断是为了在instance为null时创建实例。

静态内部类单例模式

    public class Singleton {    
         //静态内部类
        private static class SingletonHolder {    
           private static final Singleton sInstance = new Singleton();    
        }    
        private Singleton (){}    
        public static final Singleton getInstance() {    
           return SingletonHolder. sInstance;    
        }    
    } 

当第一次调用时才会初始化。第一调用getInstance方法会导致虚拟机加载SingletonHolder类,这种方式不仅能够确保线程安全,也能够保证单例对象的唯一性。推荐使用的单例实现方式。

枚举单例

    public enum Singleton {  
       INSTANCE;  
       public void doSomething() {  
       }  
    }  

写法简单,枚举和普通类一样,不仅能够有字段也能够有自己的方法。而且,枚举类的创建时线程安全的,并且在任何情况下都是一个单例。即使反序列化也不会重新生成新的实例。
而对于其他几种实现方式,要避免对象在反序列化时重新创建实例:

       private Object readResolve throw ObjectStreamException {  
             return sInstance;
       }  

使用容器实现单例模式

    //类似Spring里面的方法,将类名注册,下次从里面直接获取。 

    public class SingletonManager{  
    private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();  
        //保护的默认构造子  
    protected SingletonManager (){}  

    public static void reisterService(String key, Object instance) {
              if( !map.containsKey(key)) {map.put(key,instance);}
    }
    public static void getService(String key) {
              return map.get(key);
    }

    }  

将多种单例注入一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。
在Android中Context就是通过容器的单例模式的方式,系统核心服务以单例存在,减少了资源消耗。
Content的实现类是ContextImpl类,在虚拟机第一次加载该类时会注册各种ServiceFatcher。将这些服务以键值对的形式存储在一个HashMap中,用户只需要根据key来获取对应的ServiceFatcher,然后通过ServiceFatcher对象的getService来获取具体对象服务。当第一次获取时,或调用的ServiceFatcher的createService函数创建服务对象,然后将该对象缓存到列表中,下次再取直接村缓存中获取,避免重新创建对象,从而达到单例的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值