设计模式(design pattern)是对软件设计中广泛存在(反复出现)的各类问题,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建筑设计领域引入到计算机科学的。《设计模式》一书原先把设计模式分为建立型模式、结构型模式、行为型模式,把它们经过受权、聚合、诊断的概念来描述。javascript
建立范例所有是关于如何建立实例的。这组范例能够被划分为两组:类建立范例及对象建立范例。类建立实例在实例化过程当中有效的使用类之间的继承关系,对象建立范例则使用代理来完成其任务。包括:java
这组范例都是关于类及对象复合关系的。包括:android
这组范例都是关于对象之间如何通信的。包括:设计模式
什么是单例模式?确保一个类只有一个实例,并提供对该实例的全局访问,其构造函数私有化。安全
各类写法各有利弊,让咱们看看具体写法:并发
public class SingletonPattern {
private static SingletonPattern singletonPattern = null;
private SingletonPattern() {
}
public static SingletonPattern getInstance() {
if (singletonPattern == null) {
singletonPattern = new SingletonPattern();
}
return singletonPattern;
}
}复制代码
类加载时只是申明实例,并未实例化,当调用getInstance方法,才进行实例化,但线程不安全,多个线程并发调用getInstance方法可能会致使建立多份相同的单例出来,解决的办法就是使用synchronized关键字。app
public class SingletonPattern {
private static SingletonPattern singletonPattern = null;
public static SingletonPattern getInstance() {
synchronized (SingletonPattern.class) {
if (singletonPattern == null)
singletonPattern = new SingletonPattern();
}
return singletonPattern;
}
}复制代码
synchronized保证一个时间内只能有一个线程获得执行,另外一个线程必须等待当前线程执行完才能执行,使得线程安全。缺点每次调用getInstance方法都进行同步,形成了没必要要的同步开销。函数
public class SingletonPattern {
//饿汉模式
private static final SingletonPattern singletonPattern = new SingletonPattern();
private SingletonPattern() {
}
public static SingletonPattern getInstance() {
return singletonPattern;
}
}复制代码
类加载时就已经进行实例化,类加载较慢,但获取对象速度快,线程安全。oop
public class SingletonPattern {
private static volatile SingletonPattern singletonPattern = null;
private SingletonPattern() {
}
public static SingletonPattern getInstance() {
//第一层校验,为了不没必要要的同步
if (singletonPattern == null) {
synchronized (SingletonPattern.class) {
//第二层校验,实例null的状况下才建立
if (singletonPattern == null)
singletonPattern = new SingletonPattern();
}
}
return singletonPattern;
}
}复制代码
这里使用了volatile关键字,由于多个线程并发时初始化成员变量和对象实例化顺序可能会被打乱,这样就出错了,volatile能够禁止指令重排序。双重校验虽然在必定程度解决了资源的消耗和多余的同步,线程安全问题,但在某些状况仍是会出现双重校验失效问题,即DCL失效。ui
public class SingletonPattern {
private SingletonPattern() {
}
private static class SingletonPatternHolder {
private static final SingletonPattern singletonPattern = new SingletonPattern();
}
public static SingletonPattern getInstance() {
return SingletonPatternHolder.singletonPattern;
}
}复制代码
第一次调用getInstance方法时加载SingletonPatternHolder 并初始化singletonPattern,这样不只能确保线程安全,也能保证SingletonPattern类的惟一性。
SingletonManager
public class SingletonManager {
private SingletonManager() {
}
private static Map<String, Object> instanceMap = new HashMap<>();
public static void registerInstance(String key, Object instance) {
if (!instanceMap.containsKey(key)) {
instanceMap.put(key, instance);
}
}
public static Object getInstance(String key) {
return instanceMap.get(key);
}
}复制代码
SingletonPattern
public class SingletonPattern {
SingletonPattern() {
}
public void doSomething() {
Log.d("wxl", "doSomeing");
}
}复制代码
代码调用:
SingletonManager.registerInstance("SingletonPattern", new SingletonPattern());
SingletonPattern singletonPattern = (SingletonPattern) SingletonManager.getInstance("SingletonPattern");
singletonPattern.doSomething();复制代码
根据key获取对象对应类型的对象,隐藏了具体实现,下降了耦合度。
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
Log.d("wxl", "SingletonEnum doSomeing");
}
}复制代码
代码调用:
SingletonEnum.INSTANCE.doSomething();复制代码
更加简洁,线程安全,还能防止反序列化致使从新建立新的对象,而以上方法还需提供readResolve方法,防止反序列化一个序列化的实例时,会建立一个新的实例。枚举单例模式,咱们可能使用的不是不少,但《Effective Java》一书推荐此方法,说“单元素的枚举类型已经成为实现Singleton的最佳方法”。不过Android使用enum以后的dex大小增长不少,运行时还会产生额外的内存占用,所以官方强烈建议不要在Android程序里面使用到enum,枚举单例缺点也很明显。
AccessibilityManager
public final class AccessibilityManager {
static final Object sInstanceSync = new Object();
private static android.view.accessibility.AccessibilityManager sInstance;
public static AccessibilityManager getInstance(Context context) {
synchronized (sInstanceSync) {
if (sInstance == null) {
//省略部分代码
sInstance = new AccessibilityManager(context, null, userId);
}
}
return sInstance;
}
}复制代码
InputMethodManager
public final class InputMethodManager {
static android.view.inputmethod.InputMethodManager sInstance;
public static InputMethodManager getInstance() {
synchronized (InputMethodManager.class) {
if (sInstance == null) {
//省略部分代码
sInstance = new InputMethodManager(service, Looper.getMainLooper());
}
return sInstance;
}
}
}复制代码
我开通了小密圈,链接彼此,一块儿进步~
什么是小密圈?小密圈是一个拥有共同话题、目标的人在一块儿使用的朋友圈。它做为高品质知识社群,需付费加入。
为何我要建立小密圈,是为个人读者们建立一个更好的互动空间,让读者能够很方便联系到另外一个读者。
为何是收费的,收费是最好的门槛,是一种很好的筛选机制。
这里咱们除了创建联系,我还会不按期分享一些过来人的经验和总结,不止于Android 。