《架构整洁之道》读书笔记(三)——设计原则

2019-01-24

五大设计原则被归纳为一个简单的单次——SOLID。这五个原则在作者的另一本书《敏捷软件开发(原则、模式与实践)》 中有更加详细的描述。

SOLID分别代表:

  • SRP : 单一责任原则
  • OCP : (对扩展)开放、(对修改)封闭原则
  • LSP : 里氏替换原则
  • ISP : 接口隔离原则
  • DIP : 依赖倒置原则

本书的主要内容是讲软件架构,而SOLID这五大原则更多属于详细设计层面,用作者的话说就是研究“如何将函数和数据结构安排到类(class)中,以及类之间是如何互相连接的。”这里的“类(class)”并非侠义地指OOP语言中的“类”概念,而是广义地指“以一定的耦合性组合在一起的函数与数据”。作者在本书中除了简要地介绍了这五个原则的含义外,更多地是考察了它们在架构设计层面的指导意义。

SRP还可以被表述为“一个模块应该只服务一个Actor”。这里的Actor我理解和Use Case分析方法中的Actor应该是同样的含义。

在进行面向对象分析的时候会建模(抽象)出实体类,这样一个实体类是需要服务多个Actor、包含多个Actor需要的业务逻辑的。到了设计和实现阶段,这个一个实体类并不对应一个单独的“Entity”类。这里作者给出两个设计方案:

一种是一个Facade类提供分析阶段定义的该实体对外提供的服务(操作),然后将针对每个Actor的服务的实现分离在不同的类中,由Facade类进行调用,这些类再会使用到保存实体属性的类;

另一种是由包含实体属性的类提供Facade方法,对应分析阶段定义的实体操作,然后同样将针对每个Actor的服务的实现分离在不同的类中,由这些Facade方法调用。

我理解第一种方法得到的一系列类组成的模块比较接近DDD中所说的Bounded Context。

另外,目前在使用Spring开发软件系统中,不少程序员会简单地将操作一个实体类(或数据库表)的程序一股脑地放在一个Controller或Service类中。这时应该参考SRP原则来考虑Controller类与Service类的功能划分和设计。

在介绍OCP的时候,作者第一次提到了“低层组件依赖高层组件”的原则。离系统边界(输入/输出)越近的组件层次越低;离边界越远、离核心越近的组件层次越高。数据库等数据持久化设施也算输入,所以DAO比实体类层次低。很多Web应用的软件架构图会从上到下来画Controller、Service、实体类、DAO、数据库,而在本书中,以及其它一些书中则使用同心圆或六边形(如DDD)来表示软件架构。在圆心的一般是最高层次的组件——实体类。在书的后面部分还有对这个原则的更详细描述。

在介绍ISP的时候作者提出了:“包含”声明创造出源代码之间的依赖关系。而对这种依赖关系的管理是软件架构设计的核心问题之一。“包含”声明就是Java中的“import”,C中的“include”,其它一些语言中的“use”、“require”等等。在静态类型的编程语言中,这种依赖关系意味着被依赖组件变化后,依赖它的组件必需要重新编译和部署。动态类型的语言则消除了这样的限制。



blog comments powered by Disqus