--- 设计模式口水话 --- #### 目录 1. 六大设计原则 2. 单例模式 3. 工厂模式 4. 建造者模式 5. 代理模式 6. 装饰器模式 7. 适配器模式 8. 观察者模式 9. 责任链模式 #### 六大设计原则 六大设计原则分别是单一职责原则、开闭原则、里式替换原则、接口隔离原则、依赖反转原则及迪米特原则。 ##### 单一职责原则 单一职责原则意思是一个类只做一件事。也就是说,不要设计大而全的类,要设计粒度小、功能单一的类。 ##### 开闭原则 开闭原则是指对扩展开放,对修改关闭。具象来说,就是添加一个新的功能时,优先考虑在已有代码的基础上扩展代码,而非修改已有代码,这也要求我们要能写出扩展性好的代码。对扩展开放是为了应对变化(需求),对修改关闭是为了保证已有代码的稳定性,最终结果是为了让系统更有弹性。 ##### 里式替换原则 里式替换原则是指子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变以及正确性不会被破坏。听起来有点运行时多态的味道,但是里式替换作为一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。一些常见的违背里式替换原则的例子有,子类的方法重写违背了父类声明要实现的功能、子类违背父类对输入/输出/异常的约定、子类违背父类注释中所罗列的任何特殊说明等。简单来说,就是子完美继承了父类的设计初衷,并做了增强。 ##### 接口隔离原则 接口隔离原则是指客户端不应该依赖于它不需要的接口。 ##### 依赖反转原则 依赖反转是指高层模块不要依赖于低层模块,它们应该通过抽象来相互依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。 依赖反转容易跟控制反转、依赖注入相混淆。控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的控制指的是对程序执行流程的控制,而反转指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员反转给了框架。依赖注入是一种具体的编码技巧,我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式注入给类来使用。 ##### 迪米特法则 即最小知识原则。说的是,不该有直接依赖关系的类,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好,每个类都应该少了解系统的其他部分,一旦发生变化,需要了解这一变化的类就会比较少。它和单一职责的目的都是实现高内聚低耦合,但是出发的角度不一样,单一职责是从自身提供的功能出发,迪米特法则是从关系出发。 #### 单例模式 单例模式保证一个类仅有一个实例,并提供一个访问它的全剧访问点。它的实现有饿汉式、懒汉式、DCL、静态内部类和枚举。 单例模式的应用场景有避免资源访问冲突、表示业务概念上的全剧唯一类。 在 Android 中,常用的单例类有 LayoutInflater、LocalBroadcastManager 等。 #### 工厂模式 工厂模式可以细分为三种类型:简单工厂、工厂方法和抽象工厂。 当创建逻辑比较复杂时,就可以考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。何为创建逻辑毕竟复杂呢?主要有两种情况,第一种情况是类似规则配置解析的例子,代码中存在 if-else 分支判断,动态的根据不同的类型创建不同的对象。针对这种情况,我们就可以考虑使用工厂模式,将这一大块的 if-else 创建对象的代码抽离出来,放到工厂类中。还有一种情况是,尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,比如前面提到的要组合其他类对象,做各种初始化操作,在这种情况下,我们也可以考虑使用工厂模式。 常见的工程模式有 DataFormat 类、String.valueOf 等等。 #### 构建者模式 构建者模式即 Builder 模式。如果一个类中有很多属性,为了避免构造函数的参数列表很长,影响代码的可读性和易用性,我们可以通过构造函数配合 setXxx() 方法来解决。不仅可以控制参数的必要性,还可以对参数进行合法性校验。 在 Android 中,最典型的应用莫过于 AlertDialog 了。 #### 代理模式 代理模式是指在不改变原始类的情况下,通过引入代理类来给原始类附加功能。代理可以分为静态代理和动态代理。 静态代理的实现比较简单,就是把实际的对象通过构造函数传给代理类,代理类可以在原有的基础上添加一些附加功能。动态代理不必像静态代理事先为每个原始类编写代理类,他可以在运行时动态的创建原始类的代理类,然后在系统中用代理类替换带原始类。在 Java 中的实现也比较简单,毕竟提供了InvocationHandler 来做,但是 Java 中的动态代理只能代理接口,如果想代理类就要使用 cglib 了。 在做插件化,Hook Activity 的生命周期时,就可以使用动态代理替换掉 ActivityThread 的 H 类的 handleMessage 方法。 ####