美文网首页java学习Android 设计模式
Android的设计模式—六大原则及单例模式

Android的设计模式—六大原则及单例模式

作者: 苏州韭菜明 | 来源:发表于2019-05-27 22:05 被阅读11次

    一直想总结安卓的设计模式,简书给推荐了这么优秀的文章,故不再重复造轮子。

    文章转载自四月葡萄

    TIM截图20190527220532.png

    Android的设计模式-设计模式的六大原则

    1.单一职责原则(Single Responsibility Principle, SRP)

    定义:一个类应只包含单一的职责。

    • 一个类职责过大的话,首先引起的问题就是这个类比较大,显得过于臃肿,同时其复用性是比较差的。
    • 其次就是如果修改某个职责,有可能引起另一个职责发生错误。这是我们极力所避免的,因此设计一个类时我们应当去遵循单一职责原则。

    2.开放封闭原则(Open - ClosedPrinciple ,OCP)

    定义:一个模块、类、函数应当是对修改关闭,扩展开放。

    • 修改原有的代码可能会导致原本正常的功能出现问题。
    • 因此,当需求有变化时,最好是通过扩展来实现,增加新的方法满足需求,而不是去修改原有代码。

    3.里氏代换原则( Liskov Substitution Principle ,LSP )

    定义:使用父类的地方能够使用子类来替换,反过来,则不行。

    • 使用子类对象去替换父类对象,程序将不会产生错误
    • 因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
    • 需要注意的是:
      • 子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。如果一个方法只存在子类中,没有在父类中声明,则无法在以父类定义的对象中使用该方法。
      • 父类应当被尽量设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现

    4.依赖倒转原则( Dependence Inversion Principle ,DIP )

    定义:抽象不应该依赖于细节,细节应当依赖于抽象。

    • 即要面向接口编程,而不是面向具体实现去编程。
    • 高层模块不应该依赖低层模块,应该去依赖抽象。

    5.接口隔离法则(Interface Segregation Principle,ISL)

    定义:一个类对另一个类的依赖应该建立在最小的接口上。

    • 一个类不应该依赖他不需要的接口。
    • 接口的粒度要尽可能小,如果一个接口的方法过多,可以拆成多个接口。

    6.迪米特法则(Law of Demeter, LoD)

    定义:一个类尽量不要与其他类发生关系

    • 一个类对其他类知道的越少,耦合越小。

    • 当修改一个类时,其他类的影响就越小,发生错误的可能性就越小。

    Android的设计模式-单例模式

    1.定义

    确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。

    2.介绍

    单例模式属于创建类模式。
    单例模式有以下特点:

     1. 单例类只能有一个实例。
     2. 单例类必须自己创建自己的唯一实例。
     3. 单例类必须给所有其他对象提供这一实例。
    

    3.实现

    3.1 懒汉式(线程不安全)

    //单例类
    public class Singleton {
        private Singleton() {
        }
    
        private static Singleton single = null;
    
        public static Singleton getInstance() {
            if (single == null) {
                single = new Singleton();  //在第一次调用getInstance()时才实例化,实现懒加载,所以叫懒汉式
            }
            return single;
        }
    } 
    
    • 优点:实现了懒加载的效果。
    • 缺点:线程不安全。

    3.1 懒汉式(线程安全)

    //单例类
    public class Singleton {
        private Singleton() {
        }
    
        private static Singleton single = null;
    
        public static synchronized Singleton getInstance() { //加上synchronized同步 
            if (single == null) {
                single = new Singleton();
            }
            return single;
        }
    }  
    
    • 优点:实现了懒加载的效果,线程安全。
    • 缺点:使用synchronized会造成不必要的同步开销,而且大部分时候我们是用不到同步的。

    3.3 双重检查锁定(DCL)

    public class Singleton {
        private volatile static Singleton singleton; //volatile 能够防止代码的重排序,保证得到的对象是初始化过
    
        private Singleton() {
        }
    
        public static Singleton getSingleton() {
            if (singleton == null) {  //第一次检查,避免不必要的同步
                synchronized (Singleton.class) {  //同步
                    if (singleton == null) {   //第二次检查,为null时才创建实例
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    } 
    
    • 优点:懒加载,线程安全,效率较高
    • 缺点:volatile影响一点性能,高并发下有一定的缺陷,某些情况下DCL会失效,虽然概率较小。

    3.4 饿汉式

    //单例类.   
    public class Singleton {
        
        private Singleton() {//构造方法为private,防止外部代码直接通过new来构造多个对象
        }
    
        private static final Singleton single = new Singleton();  //在类初始化时,已经自行实例化,所以是线程安全的。
    
        public static Singleton getInstance() {  //通过getInstance()方法获取实例对象
            return single;
        }
    }  
    
    • 优点:写法简单,线程安全。
    • 缺点:没有懒加载的效果,如果没有使用过的话会造成内存浪费。

    3.5 静态内部类

    public class Singleton {
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            //第一次调用getInstance方法时才加载SingletonHolder并初始化sInstance
            return SingletonHolder.sInstance;
        }
        
        //静态内部类
        private static class SingletonHolder {
            private static final Singleton sInstance = new Singleton();
        }
    }
    
    • 优点:懒加载,线程安全,推荐使用

    3.6 枚举单例

    public enum Singleton {
    
        INSTANCE;   //定义一个枚举的元素,它就是Singleton的一个实例
    
        public void doSomething() {
        }
    }  
    
    • 优点:线程安全,写法简单,能防止反序列化重新创建新的对象。
    • 缺点:可读性不高,枚举会比静态常量多那么一丁点的内存。

    3.7 使用容器实现单例模式

    //单例管理类
    public class SingletonManager {
        private static Map<String, Object> objMap = new HashMap<String, Object>();
    
        public static void registerService(String key, Object instance) {
            if (!objMap.containsKey(key)) {
                objMap.put(key, instance);//添加单例
            }
        }
    
        public static Object getService(String key) {
            return objMap.get(key);//获取单例
        }
    }
    
    • 优点:方便管理。
    • 缺点:写法稍复杂。

    4.注意事项

    1. 使用反射能够破坏单例模式,所以应该慎用反射
        Constructor con = Singleton.class.getDeclaredConstructor();
        con.setAccessible(true);
        // 通过反射获取实例
        Singleton singeton1 = (Singleton) con.newInstance();
        Singleton singeton2 = (Singleton) con.newInstance();
        System.out.println(singeton1==singeton2);//结果为false,singeton1和singeton2将是两个不同的实例
    
    • 可以通过当第二次调用构造函数时抛出异常来防止反射破坏单例,以懒汉式为例:
    public class Singleton {
        private static boolean flag = true;
        private static Singleton single = null;
    
        private Singleton() {
            if (flag) {
                flag = !flag;
            } else {
                throw new RuntimeException("单例模式被破坏!");
            }
        }
    
        public static Singleton getInstance() {
            if (single == null) {
                single = new Singleton();
            }
            return single;
        }
    }  
    
    1. 反序列化时也会破坏单例模式,可以通过重写readResolve方法避免,以饿汉式为例:
    public class Singleton implements Serializable {
        private Singleton() {
        }
    
        private static final Singleton single = new Singleton();
    
        public static Singleton getInstance() {
            return single;
        }
    
        private Object readResolve() throws ObjectStreamException {//重写readResolve()
            return single;//直接返回单例对象
        }
    } 
    

    5.应用场景

    • 频繁访问数据库或文件的对象。
    • 工具类对象;
    • 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;

    6.优点

    • 内存中只存在一个对象,节省了系统资源。
    • 避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。

    7.缺点

    • 获取对象时不能用new
    • 单例对象如果持有Context,那么很容易引发内存泄露。
    • 单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。

    相关文章

      网友评论

        本文标题:Android的设计模式—六大原则及单例模式

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