1.开放封闭原则
软件实体(类、模块、函数等等)应该对扩展开放,对修改关闭。是对扩展和修改两个行为的一个原则。
强调的是用抽象构建框架,用实现扩展细节。开放封闭原则是面向对象设计的核心所在,遵循这个原则可以提高软件系统的可扩展性、可复用性、可维护性。让我们尽可能不修改源代码,但是可以增加新功能(开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而对于应用程序中每个部分都刻意进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要)。
无论模块是多么的封闭,都会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生变化的变化种类,然后构建抽象来隔离那些变化。查明可能发生的变化所等待的时间越长,要创建正确的抽象就越困难,所以我们希望开发工作展开不就就知道可能发生的变化。
图解
在某个项目中,我这边的业务单据需要和OA进行交互。交互的流程都是一致的,以前没启动流程的就启动流程,以前启动过流程的就重新启动流程。但是流程数据和业务单据是深度绑定的,每个业务单据的流程数据都不一致。于是用抽象类将流程步骤封装,用一个抽象方法完成对流程数据的封装,各单据自行封装。就是开放封闭原则的体现
2.里氏替换原则
所有引用基类对象的地方能够透明地使用其子类的对象(子类型必须能够替换掉他们的父类)
一个软件实体,如果使适用一个父类的话,那一定也适用于其子类,而且他察觉不出父类对象和子类对象的区别(我喜欢动物,所以我喜欢狗;但是我喜欢狗,我却不一定喜欢动物)。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没发生变化。使用里氏替换原则可以约束继承泛滥,是开闭原则的一种体现 引申含义:子类可以扩展父类的功能,但不能改变父类原有的功能。
-
子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法;
-
子类可以增加自己的特有方法(因为依赖倒置原则,最好不要增加公共方法);
-
当子类方法重载父类方法时,方法的前置条件(即方法的输入/入参)要比父类的方法输入参数更加宽泛;
- 避免使用父类对象调用该方法和使用子类对象调用该方法时因为子类对象入参更严格导致,调用了子类的该方法,从而调用结果不一致了,违背历史替换原则
只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
3.依赖倒置原则
抽象不应该依赖于细节,细节应该依赖于抽象。讲人话就是要面向接口编程,不要面向实现编程
依赖倒置原则指导我们在程序代码的关联关系或者方法出入参上,应该尽量引用高层抽象,而不要使用具体的实现类。为了确保该原则的应用,实现类应该之实现接口或抽象类声明的的方法(又因为里氏替换原则,确切的说只实现抽象方法),而不要给出多余的方法,否则将无法调用到在子类增加的新方法(都是依赖的高层)。是里氏替换是依赖倒置的基础。 基于接口编程,减少了类于类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性。
4.单一职责原则
就一个类而言,应该仅有一个引起他变化的原因。
将职责分别赋予不同的类,后期需求变更维护互不影响,可以降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计在面对变化时,遭受意想不到的破坏。单一职责原则是实现高内聚、低耦合的指导方针。
5.接口隔离原则
使用多个专门的接口,而不是使用一个单一的总接口,客户端不应该依赖他不需要的接口。
这个原则指导我们在设计接口时应当注意以下几点:
- 一个类对一类的依赖应该建立在最小接口之上;
- 建立单一的接口,不要建立庞大臃肿的接口;
- 尽量细化接口,接口中的方法尽量少(不是越少越好,掌握度);
接口隔离原则符合我们常说的高内聚低耦合的设计思想,接口责任划分更加明确。从而使得类具有很好的可读性、可扩展性和可维护性。我们在设计接口的时候要考虑业务模型,包括以后又可能发生变更的地方还要做一些预判。
图解
6.迪米特法则(最少知识原则)
如果两个类不必彼此直接通信,那么两个类就不应当发生直接的相互作用。如有需要可以通过第三方转发
迪米特法则的前提是,在类的结构设计上,每一个类都应当尽量降低成员的访问权限,其根本思想是强调了类之间的松耦合。类之间的耦合越低,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及 。只和朋友交流,不和陌生人说话,出现在成员变量、方法输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。
图解
7.合成复用原则
合成复用原则是指尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的。
避免复用时滥用继承,合理使用组合关系,增加灵活性。
8.设计原则总结
在实际开发过程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、时间、成本、质量,不是刻意追求完美,要在适当的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构。