设计模式是一套代码设计经验的总结,对设计模式的理解也根据个人能力经验水平的不同而不同,就以 Android 程序开发作为例子,对于很多简单的 app 的代码架构设计一般觉得 View 层通过回调的方式直接和 Data 层直接打交道没什么问题,方便简单,一个Activity 解决所有事。但是随着业务复杂度的提高,你会越来越发现用这种简单的架构做起来以后对于后期维护以及功能扩展简直是一个灾难。
所以在 Android 中有了各种不同的代码架构如 MVC、MVP、MVVM等等,最近准备启动一个开源github客户端项目,权衡利弊以后,我决定在代码架构上面使用 MVP 模式来实现解耦,但是在理解学习这些模式之前,有必要好好回顾一下设计模式中的六大原则。
六大原则
-
单一职责原则
( Single Responsibility Principle,简称 SRP
)
- 简述:引起类变更的原因仅有一个,即一个类只负责一项职责。
- 问题来源:假如类A有两个职责 A1,A2,当 A1 或者 A2 有修改的时候,有可能影响另一个职责的正常工作。
- 解决方法:遵循单一职责原则,对于不同的职责分别建立不同的类 B,C 去实现,这样在修改B这个职责类的时候不会影响到C这个职责的功能。
- 优点:类的复杂度降低,提高可读性和系统维护性,降低程序变更引起的风险。
-
里氏替换原则
( Liskov Substitution Principle,简称 LSP
)
- 简述:所有使用基类的地方都能够正常使用其子类,子类可以扩展父类的功能,但不能改变原有的功能。
- 问题来源:父类 A 中有一个方法 func() ,然后 A 的子类 B 重写了 func() ,新增了 func1(),这样就导致父类调用 func() 方法的时候可能用了子类 B 的实现导致错误,违背里氏替换原则。
- 解决方案:在写继承类的时候除了新增方法外,尽量不要重写或重载父类的方法。
- 优点:降低程序的出错率,增强代码复用性。
-
依赖倒置原则
( Dependence Inversion Principle,简称 DIP
)
- 简述:高层模块不应该依赖低层模块,二者都依赖抽象;细节依赖抽象,抽象不依赖细节。(Program to an interface,not an implementaction),核心思想就是面向接口编程。
- 问题来源:类 A 直接依赖具体实现类 B,假如要改为实现类 C,则需要改动A的代码。A 一般是负责复杂业务逻辑的高层模块,类 B 和 C 应该是低层模块,负责基本原子操作,修改 A 可能会带来出错的风险。
- 解决方案:使 A 依赖于 接口 I,具体实现类 B 和 C 都实现 接口 I,修改具体的依赖类不需要改动 A 的代码。
- 优点:高层模块不需要关注具体细节,更有利于模块化,在大型项目下能够很好的体现。
-
接口隔离原则
( Interface Segregation Principle,简称 ISP
)
- 简述:一个类对另一个类的依赖应该建立在最小的接口上面,不应该依赖不需要的接口。
- 问题来源:一个过于臃肿的接口在写实现类的时候导致实现类依赖不需要的接口方法。
- 解决方案:一个接口提供的职责过于臃肿的话应该要为具体的类拆分成几个专有的细化的接口,而不是全放入一个接口中。
-
注意点:
- 接口的大小要适度,过多太冗余,过少导致接口过大,设计复杂化。
- 只给调用类暴露需要的方法。
- 提高内聚,减耦合。用最少的方法完成更多的事情。
-
迪米特法则(Law of Demeter,简称 LoD
)
- 简述:又叫做最少知识原则(Least Knowledge Principle,KLP)类之间的解耦,一个对象对另一个对象的了解越少越好。
- 问题来源:假如你要写一个计算闰年的工具类,那我只要知道这个工具类提供一个 calculate(time) 的方法就行了,具体这个工具类是怎么计算的作为调用类并不需要知道。
- 解决方案:一个类所提供的方法应该尽量由自己去解决而少依赖外部的类。
- 注意点:能够实现类与类之间的解耦,但是过分使用这个法则的话会导致中介类的大量增加,增大系统的复杂度,所以使用迪米特法则的时候要权衡利弊,既要结构清晰,又要高内聚,低耦合。
-
开放封闭原则(Open Close Principle,简称 OCP
)
- 简述:一个软件实体应该对扩展开放,对修改关闭。
- 问题又来:在面对升级维护对原有代码进行修改时,可能会给旧代码引入错误,这样会导致旧代码的可用性降低,而且需要重写测试代码正确性。
- 解决方法:当软件进行变化时,尽量通过扩展来进行实现,而不是通过修改。
原文
http://zalezone.cn/2017/01/20/设计模式六大原则review/