知识卡片

分层架构解耦的闭合层原则与依赖倒置

结构图卡

内容

[[层次化风格]]的解耦核心是”闭合层”原则:每一层都标记为闭合,意味着请求从一层移动到另一层时必须经过它正下方的层——例如源自表现层的请求必须先经过业务层,再经持久层,最后才能到达数据库层,不能跨层直接调用。这体现了分层架构的关键原则:每层只能与位于其下方的层发生耦合。对系统分层处理、按功能最终呈现做职责分离后,某一层内的改变通常不会影响其他层的组件——改变被隔离在该层内部,从而获得较低的耦合度;反之,如果设计中出现跨层调用(比如控制层绕过业务层,直接把持久层数据用于表现层呈现),架构看似分层,实际已经失去了分层的意义。经典分层设计前需要牢记两条原则:底层模块不应依赖高层模块,两者都应依赖抽象;抽象不应依赖细节,细节应依赖抽象——这正是达成高内聚低耦合目标的基础。这两条原则在领域驱动设计(DDD)的分层架构中体现得尤其具体:传统三层架构(用户界面层/业务逻辑层/数据访问层)常见的失败模式是代码集中在数据访问层(DAL),导致DAL和业务逻辑层(BLL)大量交叉,很多人索性去掉了BLL,结果三层架构名存实亡、耦合度反而很大。DDD分层架构分四层(用户接口层、应用层、领域层、基础设施层,领域层居中,其上是用户接口层和应用层,其下是基础设施层)——领域层或多或少需要使用基础设施层的能力,但基础设施层位于领域层下面,若让基础设施层向上直接引用领域层会增加耦合、违反分层原则。解决办法是”依赖倒置原则”:通过改变层间的依赖关系,让底层服务依赖高层组件提供的接口(而不是高层依赖底层的具体实现)——具体做法是把基础设施层重新放到所有层的最上方(在依赖关系图上倒置过来),这样领域层定义接口、基础设施层实现并依赖这些接口,领域层本身不再向下依赖具体的基础设施实现,从而在保留基础设施能力的同时,避免了”底层反向依赖上层”这个违反分层原则的耦合。

结构图

flowchart TD
    A[用户接口层] --> D[领域层]
    B[应用层] --> D
    D -.定义接口.-> C["基础设施层<br/>(依赖倒置:实现领域层定义的接口,而非领域层直接依赖它)"]

参考来源

- 位置:《软件架构理论与实践》第18章《软件架构解耦》"18.2 分层架构及其解耦"节(源文件:_epub-src/OEBPS/text00146.html) - 结论依据:原文说明"闭合层意味着,当请求从一个层移动到另一个层时,它必须经过它正下方的层……这体现了分层架构的一个重要原则:每层只能与位于其下方的层发生耦合",并说明DDD分层架构中"由于基础设施层位于领域层的下面,从基础设施层向上引用领域层会增加耦合度,并且违反了分层架构的原则……文献提出一种解决办法:依赖倒置原则",直接支撑本卡片的结构图与内容解释。 - 原始内容:底层模块不应该依赖于高层模块,两者都应该依赖于抽象。②抽象不应该依赖于细节,细节应该依赖于抽象……根据定义低层服务应该依赖于高层组件所提供的接口(比如用户接口层、应用层和领域层),图18-3为依赖倒置原则的一种表达方式,其中将基础设施层放在所有层的最上方。