rk呓语

reposkeeper

SOLID 原则小记

solid

在面向对象编程中,有5大原则,用来指导在面向对象编程过程中,对象和类的设计。这5个原则的首字母组合起来就叫“SOLID”。当这些原则一起被应用时,创建一个可扩展、可维护的程序就成了可能。

这5个原则是:

  1. Single Responsibility Principle:单一功能原则,对象应该仅具有一种单一功能。
  2. Opened Closed Principle:软件对于扩展是开放的,对于修改是封闭的。
  3. Liskov Substitution Principle:里氏替换原则,程序中的对象在可以不改变程序的正确性的前提下,被它的子类替换。
  4. Interface Segregation Principle:接口隔离原则,多个特定客户端的接口,好过一个宽泛用途的接口。
  5. Dependency Inversion Principle:依赖反转原则,依赖于抽象而不是一个实例。

上面的这5条原则,组成了现代程序设计的基石,S.O.L.I.D 原则在整个软件行业是相对统一的标准,也是最基础的编码标准。但是这几条遵循起来的时候并不是特别容易。我觉得有些原则的边界是有些模糊的。这段时间一直尝试去实践,简单说一下心得。

如何理解 LSP、DIP

在5条原则中,LSP、DIP 两种原则是没有模糊边界的。

LSP用在类的继承关系中。只有符合LSP的时候,子类和父类才是 IS-A 的关系。可以在 Client 没有感知的情况 下,将父类替换成子类。这就要求子类对于父类提供的功能和行为表现是一致的。

一个典型的不符合 LSP 的实践就是:将 正方形 作为 长方形 的子类。因为正方形不能单独的修改长和宽的边长,所以,就导致了子类的行为和父类的行为是不一样的。派生类可以替换基类使用是LSP的核心。

DIP 是用来做对象之间解耦而使用的一个原则。
你不会想把灯泡直接焊在电线上的。`依赖要通过抽象来依赖。不能直接依赖一个实体,否则就会导致耦合太强,任何上层和下层任何一方想要有改变,都必须同步更改另一方。

此外,如果从上到下的设计中,上层依赖下层,那就无法体现出层级的概念,没有办法解耦了。此外设计的原则中,抽象不依赖细节,细节依赖抽象。

如何定义模糊的边界

SRP、OCP、ISP 都属于有模糊边界的原则。

比如说:SRP中,如何定义一个单一功能呢?打印可以作为单一功能,还是说 打印WORD打印PDF 都应该作为单一功能呢?

对于SRP,Bob大叔给出了一个总结,一个类只有一个修改的理由。但这个理由也不够充分。

因为,在实际应用中,哪些修改属于一个修改的理由其实很难界定。我的经验看来,如果一个类的功能中的动词可以在此类中有多个宾语,那么就可以认为这个类并不是一个单一功能的类。

对于OCP,容易模糊的是,哪些属于修改,哪些属于扩展?比如一个打印终端报表的类,要在表格上添加一个表头,这属于扩展还是修改呢?修复一个打印的BUG是扩展还是修改呢?

所以,在我看来,修改应该是扩展的子集,可以通过扩展来修改某些功能。但是,对于类内部机制的修改应该是封闭的,比如一些临时变量、临时存储的机制等等。

对于ISP,其实和SRP是一样的,很难定义什么是宽泛的接口。要多细的粒度,才能称得上特定细粒度呢?在我看来,这个范围可以较SRP稍微宽泛一些。比如:如果可以用同一个动词来描述的功能,那么可以在一个接口中。

Ext4 文件系统简析

上一篇

Golang sync.Pool 源码解析

下一篇
评论
发表评论 说点什么
还没有评论
113
0