您的位置:首页 > 移动开发 > Android开发

Android设计模式-单例模式

2016-07-27 13:44 344 查看

单例模式介绍

最近在学习设计模式,本篇博文主要是对《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函数创建服务对象,然后将该对象缓存到列表中,下次再取直接村缓存中获取,避免重新创建对象,从而达到单例的效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 设计模式 java