前言
程序员技术精进之路上设计模式是绕不开的话题。尽可能多的使用设计模式可以让我们的代码更清晰,更有条理。现在较经常使用的设计模式有数种之多。这些设计模式大都遵循六大基本原则,分别是:
- 单一职责原则
- 开闭原则
- 里氏替换原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特法则
如何理解这六大基本原则呢
单一职责原则
单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
说人话就是一个类或者方法最好只用来做一件事,比如我想盖一件房子,我可以用一个类实现盖房子的所有步骤,但是有两个缺点,第一个不易阅读,第二个没法复用。第二天我想盖栋大厦,又得重新写一个更加复杂的类来实现,非常没有效率。
但是假如我把盖一个房子的所有步骤拆分开,拆分成打地基,建主体框架,埋线铺设管道等,每个步骤又可以细分到拌水泥,砌砖等等。那么我在盖大厦时不就可以复用建房子的很多步骤了么。这将大大节约开发时间。也可以方便应对今后产品需求的变更。
开闭原则
开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
任何代码在不断迭代的状态下总会遇到需求的不断变更,有时候明知道以前的代码和数据架构很烂依然需要进行支持。这时候假如我们的低层遵循了开闭原则的话,我们可以做到在不改变底层架构的情况下通过扩展新的类型支持新的需求,避免很多可以预期会出现的bug,这将极大提升程序员的幸福感。
里氏替换原则
里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。例如:我喜欢动物,那我一定喜欢狗,因为狗是动物的子类;但是我喜欢狗,不能据此断定我喜欢动物,因为我并不喜欢老鼠,虽然它也是动物。
里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
依赖倒置原则
依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
具体应尽量只实现事先定义在接口或抽象类中的方法而不增加更多私有的方法,以避免无法通过父类对象调用子类自定义方法的情况。
接口隔离原则
接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
这个可以理解为接口版的单一职责原则,即不宜将所有方法定义在总接口中,以免具体类需要实现的方法过多。应尽量保持接口的专一性,每个接口只负责一个方面。普通人的日常有吃饭,睡觉,洗澡等等,但假如我今天没怎么流汗,我就可以不实现洗澡接口,避免写洗澡的具体实现了。
迪米特法则
迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。
如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。
迪米特法则还有几种定义形式,包括:不要和“陌生人”说话、只与你的直接朋友通信等,在迪米特法则中,对于一个对象,其朋友包括以下几类:
1 当前对象本身(this);
2 以参数形式传入到当前对象方法中的对象;
3 当前对象的成员对象;
4 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
5 当前对象所创建的对象。
迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。
在具体开发环境中的应用
任何具体设计模式都是对这些原则的实践,就像笑傲江湖里的华山剑气二宗一样,气为本,剑为用。在这里就是原则为本,具体模式为用。在程序开发中常用的一些设计模式有单例模式,构建者模式,工厂模式等。
我曾用构建者模式来创建我们app自定义风格的dialog,也是模仿android原生的AlertDialogBuilder来做的,可以避免每次用到都要重新写布局文件的尴尬。Builder模式的特色就是将title,content,click事件等都保存到构造者中,让它来构造所需要的dialog。
public Builder setTitle(String title){
dialogViewModel.title = title;
return this;
}
每次set之后都要返回Builder对象本身,别的好像也没什么好说的了。