经典的设计原则,其中包括:SOLID、KISS、YAGNI、DRY、LOD等。
很多设计原则、设计思想、设计模式,都是以提高代码的扩展性为最终目的。
SOLID原则
SOLID原则并非单纯的1个原则,而是由5个设计原则组成的,它们分别是:
- SRP 单一职责原则
- OCP 开闭原则
- LSP 里氏替换原则
- ISP 接口隔离原则
- DIP 依赖倒置原则
依次对应SOLID中的S、O、L、I、D这5个英文字母。
单一职责原则 SRP(Single Responsibility Principle)
解释:一个类或者模块只负责完成一个职责(或者功能)。
也就是说不要设计大而全的类,要设计粒度小、功能单一的类。
单一职责原则是为了实现代码高内聚、松耦合,提高代码的复用性、可读性、可维护性。
开闭原则 OCP(Open Closed Principle)
解释:软件实体(模块、类、方法等)应该“对扩展开放、对修改关闭”。
添加一个新功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。
这条原则的设计初衷是:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试。我们就可以说,这是一个合格的代码改动。
有两点需要注意:第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。
里氏替换原则 LSP(Liskov Substitution Principle)
解释:子类对象能够替换程序中父类对象出现的任何地方,并且保证原来的逻辑行为不变及正确性不被破坏。
多态和里氏替换有点类似,但他们关注的角度是不一样的。多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法。它是一种代码实现思路。而里氏替换是一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。
接口隔离原则 ISP(Interface Segregation Principle)
解释:客户端不应该被强迫依赖它不需要的接口。其中“客户端”可以理解为接口的调用者或者使用者。
接口隔离原则跟单一职责原则有点类似,不过稍微还是有点区别。单一职责原则针对的是模块、类、接口的设计。而接口隔离原则相对于单一职责原则,一方面它更侧重于接口的设计,另一方面它的思考的角度不同。它提供了一种判断接口是否职责单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。
依赖反转原则 DIP(Dependency Inversion Principle)
解释:高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象来互相依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象
依赖反转原则也叫做依赖倒置原则。这条原则跟控制反转有点类似,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。
KISS 原则 (Keep It Simple and Stupid)
解释:尽量保持简单
这个原则说的意思就是,尽量保持代码简单。代码简单、逻辑清晰、也就意味着易读、易维护。我们在编写代码的时候,往往也会把简单、清晰放到首位。
KISS原则是保持代码可读和可维护的重要手段。KISS原则中的“简单”并不是以代码行数来考量的。代码行数越少并不代表代码越简单,我们还需要考虑逻辑复杂度、实现难度、代码的可读性等,而且本身就复杂的问题,用复杂的方法解决,并不违背KISS原则。除此之外,同样的代码,在某个业务场景下满足KISS原则,换一个应用场景可能就不满足了。
对于如何写出满足KISS原则的代码,指导原则是:
- 不要使用同事可能看不懂的技术来实现代码
- 不要重复造轮子,要善于使用已经有的工具类库
- 不要过度优化
YAGNI 原则(You Ain't Gonna Need It)
解释:你不会需要它
它的意思是:不要去设计当前用不到的功能;不要去编写当前用不到的代码。实际上,这条原则的核心思想是:不要过度设计。
KISS原则讲的是“如何做”的问题(尽量保持简单),而YAGNI原则说的是“要不要做”的问题(当前不需要做就不要做)。
DRY 原则(Don't Repeat Yourself)
解释:不要重复自己。可以理解为:不要写重复代码。
实现逻辑重复,但功能语义不重复的代码,并不违反DRY原则。实现逻辑不重复,但功能语义重复的代码,也算是违反DRY原则。除此之外,代码执行重复也算是违反DRY原则。
代码复用性:
- 减少代码耦合
- 满足单一职责原则
- 模块化
- 业务与非业务逻辑分离
- 通用代码下沉
- 继承、多态、抽象、封装
- 应用模板等设计模式
实际上除了上面讲到的这些方法外,复用意识也非常重要。在设计每个模块、类、函数的时候,要像设计一个外部API一样去思考它的复用性。
迪米特法则 LOD(Law of Demeter)
解释:最小知识原则。即,高内聚、松耦合。
高内聚、松耦合是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。高内聚用来指导类本身的设计,松耦合用来指导类与类之间依赖关系的设计。
所谓高内聚,就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一个类中。相近的功能往往会被同时修改,放到同一个类中,修改会比较集中。所谓松耦合指的是,在代码中,类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动也不会或者很少导致依赖类的代码改动。
不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好。每个类都应该减少了解系统的其他部分。一旦发生变化,需要了解这一变化的类就会比较少。