美文网首页Android设计模式
Android设计模式-1-单例模式

Android设计模式-1-单例模式

作者: 今阳说 | 来源:发表于2018-05-30 23:40 被阅读57次

    1. 定义:

    • 确保1个类只有1个实例化对象 ,提供一个全局访问点

    2. 优缺点

    • 优点:客户端使用单例模式的实例的时候,只需要调用一个单一的方法即可生成一个唯一的实例,有利于节约资源。
    • 缺点:首先单例模式很难实现序列化,这就导致采用单例模式的类很难被持久化,当然也很难通过网络传输;其次由于单例采用静态方法,无法在继承结构中使用。

    3. android源码中的体现:

    • 例如,加载布局时经常要创建LayoutInflater的实例,常见的有三种方法:
      - getLayoutInflater()
      - LayoutInflater.from(context)
      - (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE)
    

    其实前两种最后都是调用的最后一种,是获取系统服务经常用到的方法,这只是一个典型的单例的使用场景,其实在Android源码中用到单例的情况还有很多。

    4. 几种实现方式

    1. 饿汉式:在声明变量时就创建该实例
      • 优点:线程安全,多线程中使用不会出现创建多个实例的情况
      • 缺点:比较消耗计算机资源
        public class A {
            private static final A a = new A();
    
            private A() {
                if (a!=null)//这样可以防止通过反射创建该类的实例对象
                    throw new AssertionError();
            }
    
            public static A getInstance() {
                return a;
            }
    
            //该类的一些方法,供实例调用
            public void doSomething() {
                LjyLogUtil.i(String.format("%s: do sth....", this.getClass().getName()));
            }
        }
    
    1. 懒汉式:使用到时才创建实例
    • 优点:节省计算机资源,在单线程下能够非常好的工作
    • 缺点:在多线程下存在线程安全问题
      public class B {
            private static B b;
    
            private B() {
            }
    
            public static synchronized B getInstance() {
                if (b == null) {
                    b = new B();
                }
                return b;
            }
            
            public void doSomething() {
                LjyLogUtil.i(String.format("%s: do sth....", this.getClass().getName()));
            }
        }
    
    1. 懒汉式+双重校验锁:DCL ( Double Check Lock)
    • 优点:既解决了”懒汉式“的多线程问题,又解决了资源浪费的现象
    • 缺点:在某些情况DCL会出现失效问题,《Java并发编程实践》中提到此问题,并指出这种优化是丑陋的,不赞成使用的,而推荐使用静态内部类实现
    • DCL失效的原因:线程有可能得到一个不为null,但是构造不完全的对象。Why?造成不可靠的原因是编译器为了提高执行效率的指令重排。只要认为在单线程下是没问题的,它就可以进行乱序写入,以保证不要让cpu指令流水线中断
      /**
      *  懒汉式+双重校验锁
      *  实现Serializable接口,支持序列化
      */
      public class C implements Serializable {
            private static C c;
    
            private C() {
            }
    
            public static C getInstance() {
                if (c == null) {
                    synchronized ((C.class)) {
                        if (c == null) {
                            c = new C();
                        }
                    }
                }
                return c;
            }
    
            public void doSomething() {
                LjyLogUtil.i(String.format("%s: do sth....", this.getClass().getName()));
            }
    
            //若要避免单例对象在反序列化时生成新的对象,就必须加入下面方法
            private Object readResolve() throws ObjectStreamException {
                return c;
            }
    
       }
    
    
    1. 通过静态内部类实现单例
    • 原理:一个类直到被使用时才被初始化,而类初始化的过程是非并行的,这些都有 JLS 保证
    • 这也是我自己最常用的单例写法
      public class Dog {
    
            private Dog() {
            }
    
            public static Dog getInstance() {
                return DogHolder.dogInstance;
            }
    
            private static class DogHolder {
                private static Dog dogInstance = new Dog();
            }
    
            public void doSomething() {
                LjyLogUtil.i(String.format("%s: do sth....", this.getClass().getName()));
            }
        }
    
    1. 枚举单例:写法简单,线程安全,并且保证任何情况都是单例
    • 上面的其他实现单例方法在反序列化(提供了一个特别的钩子函数)时会创建新的单例,解决方法是如3中实现readResolve方法返回单例对象,而枚举单例则不存在此问题
      public enum D {
    
            INSTANCE;
    
            public void doSomething() {
                LjyLogUtil.i(String.format("%s: do sth....", this.getClass().getName()));
            }
        }
    
    1. 使用容器实现单例:可以管理多种类型的单例
      public class SingletonManager {
    
            private static Map<String, Object> instanceMap = new HashMap<>();
    
            private SingletonManager() {
            }
    
            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);
            }
        }
    

    相关文章

      网友评论

        本文标题:Android设计模式-1-单例模式

        本文链接:https://www.haomeiwen.com/subject/hpmxsftx.html