设计原则

2020-07-01

SOLID 原则:

S:Single Responsibility Principle,缩写 SRP。单一职责原则。

  • A class or module should have a single reponsibility。一个类或者模块只负责完成一个职责。
  • 判断类的职责是否足够单一:类中的代码行数、函数或者属性是否过多、类依赖的其他类是否过多、私有方法是否过多、是否比较难给类起一个合适的名字、类中是否有大量的方法都是集中操作类中的某几个属性
  • 单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。
  • 类拆分得过细,会适得其反,降低内聚性,也会影响代码的可维护性。

 

O:Open Closed Principle,缩写 OCP。开闭原则。

  • software entities (modules, classes, functions, etc.) should be open for extension , but closed for modification。软件实体(模块、类、方法等)应该“对扩展开放、对修改关闭”。
  • 开闭原则是解决代码扩展性问题最有效的设计原则。
  • 添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。
  • 开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发;同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。
  • 如何做到?时刻具备扩展意识、抽象意识、封装意识。
  • 最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态)。

 

L:Liskov Substitution Principle,缩写 LSP。里式替换原则。

  • If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program。(1986 年由 Barbara Liskov 提出)
  • Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it。(1996 年,Robert Martin)
  • 子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。
  • 哪些代码明显违背了 LSP?子类违背父类声明要实现的功能;子类违背父类对输入、输出、异常的约定;子类违背父类注释中所罗列的任何特殊说明
  • 里式替换原则是用来指导,继承关系中子类该如何设计的一个原则。理解里式替换原则,最核心的就是理解“design by contract,按照协议来设计”这几个字。
  • 父类定义了函数的“约定”(或者叫协议),那子类可以改变函数的内部实现逻辑,但不能改变函数原有的“约定”。这里的约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至包括注释中所罗列的任何特殊说明。

 

I:Interface Segregation Principle,缩写 ISP,接口隔离原则。

  • Clients should not be forced to depend upon interfaces that they do not use. 客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。
  • “接口”理解为一组接口集合,如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。
  • “接口”理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。
  • “接口”理解为 OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。
  • 接口隔离原则与单一职责原则的区别:单一职责原则针对的是模块、类、接口的设计;接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。

 

D:Dependency Inversion Principle,缩写 DIP。依赖反转原则。

  • High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstractions. 高层模块(high-level modules)不要依赖低层模块(low-level)。高层模块和低层模块应该通过抽象(abstractions)来互相依赖。除此之外,抽象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖抽象(abstractions)。
  • 所谓高层模块和低层模块的划分,简单来说就是,在调用链上,调用者属于高层,被调用者属于低层。
  • 这条原则主要还是用来指导框架层面的设计,高层模块不依赖低层模块,它们共同依赖同一个抽象,抽象不要依赖具体实现细节。
  • 控制反转:是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。
  • 依赖注入:是一种具体的编码技巧,不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。
  • 依赖注入框架:依赖注入框架提供的扩展点,简单配置一下所有需要的类及其类与类之间依赖关系,就可以实现由框架来自动创建对象、管理对象的生命周期、依赖注入等原本需要程序员来做的事情。

 

KISS 原则:

ConstXiong 备案号:苏ICP备16009629号-3