Android设计模式之单例模式(Singleton Pattern)

本文出自:http://www.cnblogs.com/warmwei818/p/5350837.html

个人总结学习和研究,部分内容参考《Android源码设计模式解析与实战》一书~~
 
一.  定义: 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
 也就是说,单例要满足3点:
       1、单例类只能有一个实例。
       2、单例类必须自己创建自己的唯一实例。(构造函数私有化,防止外部程序通过new来构造)。
       3、单例类必须给其他对象提供这一实例。(暴露公有静态方法或者通过枚举返回单例类对象)。

二.  使用场景: 确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源。比如说在一个应用中,应该只有一个ImageLoader实例,这个Imageloader中含有线程池、缓存系统、网络请求等,比较消耗资源。还比如访问IO和数据库等资源,就要考虑使用单例模式。
android源码中也有很多地方用了单例模式,比如说输入法管理者InputMethodManager,比如一个应用只有一个Application对象等。
 
三. 实现方式:
 
1、饿汉式单例
特点:声明静态对象的时候进行初始化静态对象,以后不再改变,天生是线程安全的。弊端:消耗资源。
1
2
3
4
5
6
7
8
9
10
public  class  Singleton {
     private  static  Singleton instance =  new  Singleton();
 
     private  Singleton() {
     }
 
     public  static  Singleton getInstance() {
         retun instance;
     }
} 
 
2、懒汉式单例
特点:声明静态对象,并在第一次调用getInstance时进行初始化。优势:延迟加载。弊端:线程不安全。
1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Singleton {
     private  static  Singleton instance =  null ;
 
     private  Singleton() {
     }
 
     public  static  Singleton getInstance () {
         if  (instance ==  null ) {
             instatnce =  new  Singleton();
         }
         return  instance;
     }
}
     
懒汉式加锁
      getInstance()静态方法添加synchronized关键字,即同步方法保证线程安全。  弊端:造成不必要的同步开销。具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Singleton {
     private  static  Singleton instance =  null ;
 
     private  Singleton() {
     }
 
     public  static  synchronized  Singleton getInstance () {
         if  (instance ==  null ) {
             instatnce =  new  Singleton();
         }
         return  instance;
     }
}
 
3、双重检查锁定(Double CheckLock)实现单例
特点:延迟加载,解决了多余的同步,线程安全。
两次判空,第一层是为了避免不必要的同步。 第二层是为了在instance为null的情况下创建实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  class  Singleton {
     private  static  Singleton instance =  null ;
      
     private  Singleton () {
     }
      
     public  static  Singleton getInstance () {
         // If already initialized, no need to get lock everytime.
         if  (instance ==  null ) {
             synchronized  (Singleton. class ) {
                 if  (instance ==  null ) {
                     instance =  new  Singleton();
                 }
             }
         }
         return  instance ;
     }
}

  

4、静态内部类单例
特点:延迟加载,线程安全。  利用Java虚拟机加载类的特性实现延迟加载和线程安全, 推荐使用的单例实现方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  class  Singleton() {
 
     private  Singleton() {
     }
     
     public  static  Singleton getInstance () {
         return  SingletonHolder.instance;
     }
     
     /**
      * 静态内部类,只有在装载该内部类时才会去创建单例对象
      */
     private  static  class  SingletonHolder {
          private  static  final  Singleton instance =  new  Singleton();
     }
 
}
 
5、枚举单例
特点:写法简单,线程简单,反序列化也不会重新创建对象。(前面四种情况在反序列化中均会生成新的实例)。
 
枚举单例虽然在Effective Java中推荐使用,但是在Android平台上却是不被推荐的。
Android官方的Training课程中明确指出:
Enums ofter require more than twice as much memory as static constants. You should strictly avoid using enums on Android.
1
2
3
4
5
6
7
8
public  enum  Singleton {
     // 定义一个枚举的元素,它就是Singleton的一个实例
     INSTANCE;
 
     public  void  doSomethig() {
         // TODO:
     }
}
 枚举在java中与普通的类一样的,不仅能够有字段,还能够有自己的方法。
 最重要的是默认枚举实例的创建是线程安全的,并且在任何情况下都是一个单例。  使用方法如下:
1
2
Singleton singleton = Singleton.INSTANCE;
singleton.doSomething();
 
6、使用容器实现单例  
脑洞打开,再来看看一种另类的实现方式。维护一个统一的管理类,注入多种单例类型,在使用时根据key获取对应类型的单例对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  class  SingletonManager {
     private  static  Map<String, Object> objMap =  new  HashMap<>();
 
     private  Singleton() {
     }
     
     public  static  void  addSingleton(String key, Object instance) {
         if  (!objMap.containsKey(key)) {
             objMap.put(key, instance);
         }
     }
 
     public  static  getSingleton(String key) {
         return  objMap.get(key);
     }
}

  

总结:  选择哪种实现方式取决于项目本身,如是否是复杂的并发环境、JDK版本是否过低,单例对象的资源消耗等。一般而言,手机客户端通常没有高并发的情况,所以具体选择哪种实现方式并不会有太大的影响。个人一般使用静态内部类的实现方式。
注意: 单例对象如果持有Context,很容易引发内存泄露,需要注意传递给单例对象的Context最好是Application Context。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值