开闭原则(Open Closed Principle)
定义:软件实体应该对扩展开放,对修改关闭。
由来:一些软件生命周期很长,必然面临维护升级等变化。而新添加的代码很容易对旧有的代码造成影响,甚至给旧有的代码带来Bug。
解决:当软件代码需要进行变动时,尽量以添加新的代码来完成,而不去修改原有的代码。也即通过扩展来完成所需要的功能的添加。
里氏替换原则(Liskov Substitution Principle)
定义:继承必须确保父类所拥有的性质在子类中仍然成立。
由来:通过子类来完成父类的任务,可能会产生问题。
解决:子类可以实现父类的抽象方法,但是不去Override父类的非抽象方法。这也算是某种意义上的开闭原则吧,尽量不要去影响旧有的代码,通过扩展(取新名字,而不是Override)来完成新功能。
依赖倒置原则(Dependence Inversion Principle)
定义:高层模块不依赖于底层模块,两者都应该依赖于抽象,抽象不依赖于细节,细节依赖于抽象。
由来:表示层、业务逻辑层以及数据访问层之间如果分得不太清楚,各模块之间交叉调用,就会带来很强的耦合性,往往会牵一发而动全身,改动一个地方,很多地方都会受到影响,增加出错的风险。
解决:主要是通过面对接口编程,将实现细节与业务逻辑分开,它们都是通过抽象的接口来完成交互的。业务逻辑只和抽象的接口打交到,而不必关注具体的实现过程。同样实现过程也不必关注业务,它只需要关注接口即抽象即可。
接口隔离原则(Interface Segregation Principle)
定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应建立在最小接口上。
由来:一个接口里完成了很多工作,但是当个功能只需要调用接口里的一小部分功能的时候,如果调用这个接口,就会做一些不必要的工作,甚至可能产生问题。
解决:一个接口尽量完成比较单一的任务,这样两个类交互时,产生的影响才会在控制范围内。
合成/聚合复用原则(Composite/Aggregate Reuse Principle)
定义:能够使用合成/聚合的,不要使用继承。合成是指局部与整体的关系;聚合则是包含的关系。
由来:继承关系是在编译时就确定了,如果想在运行时改变父类与子类的关系就不行了;另外父类改变了一定会影响到子类。继承的关系限制了更灵活地复用代码。
解决:通过使用合成/聚合来替代继承关系,达到更灵活地修改代码。
迪米特法则(Law Of Demeter)
定义:也称最少知道原则(Least Knowledge Principle),只和你最直接的类(成员变量、方法参数、方法返回值中的类)沟通,尽可能少地与其他实体发生交互。
由来:想降低类之间的耦合关系,相互之间尽量减少依赖关系。
解决:与越少的类相互越好,尽量做到低耦合高内聚。尽量做到模块化。
P.S. 经常被提到的原则还有单一职责原则(Single Responsibility Principle),一个类只应该有一个引起它变化的原因,也即一个类只负责一件事。像流水线作业一样,一位员工只负责自己的那一部分,完了就交给其他员工。
P.S. 设计模式的这几大原则,是我们设计模式的一个根本。每一个设计模式都是为了更好的完成这些设计模式的原则而总结设计出来的。设计模式的原则是基本功,而23个设计模式则是对基本功的应用。当23个设计模式能够融会贯通的时候,就可以不用固定于那23个设计模式了,而是根据这些设计模式的原则来自由设计代码。