架构简洁之道读书笔记--第四部分组件构间原则

本文探讨了组件设计原则(SOLID),特别是复用/发布等同原则、共同闭包原则和共同复用原则,强调相似类的聚合。重点介绍了如何通过无依赖环原则避免循环依赖,以及如何通过依赖反转和自上而下设计来隔离组件间的变更。还涵盖了稳定抽象原则,确保高阶策略的稳定性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读了这部分,这部分内容主要讲解我们应该将哪些内容放在一个组件中,怎样设计、处理组件中的依赖关系(如何隔离频繁的变更、打破循环依赖),具体的做法和依赖转换的内容很像。

1- 组件

SOLID 原则是用于指导我们如何将砖块砌成墙与房间的,那么组件构建原则就是用来指导我们如何将这些房间组合成房子的。
组件都是该软件在部署过程中的最小单元。设计良好的组件都应该永远保持可被独立部署的特性,这同时也意味着这些组件应该可以被单独开发。
我们常常会在程序运行时插入某些动态链接文件,这些动态链接文件所使用的就是软件架构中的组件概念。

2- 组件设计原则--组件聚合

究竟是哪些类应该被组合成一个组件呢?
REP: The Reuse/Release Equivalence Principle。复用/发布等同原则。
CCP: The Common Closure Principle。共同闭包原则。
CRP: The Common Reuse Principle。共同复用原则。


2.1- 复用/发布等同原则

软件复用的最小粒度应等同于其发布的最小粒度。
从软件设计和架构设汁的角度来看,REP 原则就是指组件中的类与模块必须是 彼此紧密相关的。也就是说,一个组件不能由一组毫无关联的类和模块组成,它们之间应该有一个共同的主题或者大方向。
但从另外一个视角来看,这个原则就没那么简单了。因为根据该原则,一个组件中包含的类与模块还应该是可以同时发布的。这意味着它们共享相同的版本号与版本跟踪,并且包含在相同的发行文档中,这些都应该同时对该组件的作者和用户有意义。---没太理解可以共同发布的意义。。。


2.2- 共同闭包原则

我们应该将那些会同时修改,并且为相同目的而修改的类放到同一个组件中,而将不会同时修改,并且不会为了相同目的而修改的那些类放到不同的组件中。
共同闭包原则的主要作用就是提示我们要将所有可能会被一起修改的类集中在一处--感觉和复用发布等同原则的第一层含义类似。
对大部分应用程序来说,可维护性的重要性要远远高于可复用性。

2.2- 共同复用原则

共同复用原则建议我们将经常共同复用的类和模块放在同一个组件中
通常情况下,类很少会被单独复用。更常见的情况是多个类同时作为某个可复用的抽象定义被共同复用。CRP 原则指导我们将这些类放在同一个组件中,而在这样的组件中,我们应该预见到会存在着许多互相依赖的类。
在共同复用原则原则中,关于哪些类不应该被放在一起的建议是其更为重要的内容。简而言之,共同复用原则原则实际上是在指导我们:不是紧密相连的类不应该被放在同一个组件里
 

感觉这三条都在强调一点:相似的、紧密联系的类放在同一组件中。

3- 组件耦合

3.1- 无依赖环原则

我们一定都有过这样的经历:当你花了一整天的时间,好不容易搞定了一段代码,第二天上班时却发现这段代码莫名其妙地又不能工作了。这通常是因为有人在你走后修改了你所依赖的某个组件。我给这种情况起了个名字——“一觉醒来综合征”

这种综合征的主要病因是多个程序员同时修改了同一个源代码文件。虽然在规模相对较小、人员较少的项目中,这种问题或许并不严重,但是随着项目的增长,研发人员的增加,这种每天早上刚上班时都要经历一遍的痛苦就会越来越多。甚至会严重到让有的团队在长达数周的时间内都不能发布一个稳定的项目版本,因为每个人都在不停地修改自己的代码,以适应其他人所提交的变更。---没有设计好组件间依赖,导致某个组件修改影响了大量其他之前正常运行的组件。

针对这个问题逐渐演化出了两种解决方案,它们都来自电信行业。第一种是“每周构建”,第二种是“无依赖环原则(ADP)”。 --笔记主要介绍无依赖环原则.

对于上述情景,我们的解决办法是将研发项目划分为一些可单独发布的组件,这些组件可以交由单人或者某一组程序员来独立完成。当有人或团队完成某个组件的某个版本时,他们就会通过发布机制通知其他程序员,并给该组件打一个版本号,放入一个共享目录。这样一来,每个人都可以依赖于这些组件公开发布的版本来进行开发,而组件开发者则可以继续去修改自己的私有版本。
每当一个组件发布新版本时,其他依赖这个组件的团队都可以自主决定是否立即采用新版本。若不采用,该团队可以选择继续使用旧版组件,直到他们准备好采用新版本为止。
这样就不会出现团队之间相互依赖的情况了。任何一个组件上的变更都不会立刻影响到其他团队。每个团队都可以自主决定是否立即集成自己所依赖组件的新版本。更重要的是,这种方法使我们的集成工作能以一种小型渐进的方式来进行。程序员们再也不需要集中在一起,统一集成相互的变更了。
如你所见,上述整个过程既简单又很符合逻辑,因而得到了各个研发团队的广泛采用。但是,如果想要成功推广这个开发流程,就必须控制好组件之间的依赖结构,绝对不能允许该结构中存在着循环依赖关系。如果某项目结构中存在着循环依赖关系,那么“一觉醒来综合征”将是不可避免的。

没有循环依赖的组件设计

不管我们从该图中的哪个节点开始,都不能沿着这些代表了依赖关系的边最终走回到起始点。也就是说,这种结构中不存在坏,我们称这种结构为有向无环图(Directed Acyclic Graph,简写为 DAG)。

 

循环依赖组件设计(糟糕的设计)

这种循环依赖立刻就会给我们的项目带来麻烦。例如,当 Database 组件的程序员需要发布新版本时,他们需要与 Entities 组件进行集成。但现在由于出现了循环依赖,Database 组件就必须也要与 Authorizer 组件兼容,而 Authorizer 组件又依赖于 Interactors 组件。这样一来,Database 组件的发布就会变得非常困难。在这里,Entities、Authorizer 及 Interactors 这三个组件事实上被合并成一个更大的组件。这些组件的程序员现在会互相形成干扰,因为他们在开发中都必须使用完全相同的组件版本。

 

消除循环依赖的方法--依赖反转法

我们可以打破这些组件中的循环依赖,并将其依赖图转化为 DAG。目前有以下两种主要机制可以做到这件事情。
应用依赖反转原则(DIP):我们可以创建一个 User 类需要使用的接口,然后将这个接口放入 Entities 组件,并在 Authorizer 组件中继承它。这样就将 Entities 与 Authorizer 之间的依赖关系反转了,自然也就打破了循环依赖关系。

 

3.2- 自上而下设计

组件结构图中的一个重要目标是指导如何隔离频繁的变更。我们不希望那些频繁变更的组件影响到其他本来应该很稳定的组件,例如,我们通常不会希望无关紧要的 GUI 变更影响到业务逻辑组件;我们也不希望对报表的增删操作影响到其高阶策略。出于这样的考虑,软件架构师们才有必要设计并且铸造出一套组件依赖关系图来,以便将稳定的高价值组件与常变的组件隔离开,从而起到保护作用。

3.3- 依赖稳定原则

依赖关系必须要指向更稳定的方向。

任何一个我们预期会经常变更的组件都不应该被一个难于修改的组件所依赖,否则这个多变的组件也将会变得非常难以被修改。

如果一个系统中的所有组件都处于最高稳定性状态,那么系统就一定无法再进行变更了,这显然不是我们想要的。事实上,我们设计组件架构图的目的就是要决定应该让哪些组件稳定,让哪些组件不稳定

抽象组件--稳定组件

创造新组件这种做法挺奇怪的,因为这样的组件中几乎不包含任何可执行的代码!但事实上,这种做法在 C# 或者 Java 这种静态类型语言中是非常普遍的,而且也必须这样做。因为这些抽象组件通常会非常稳定,可以被那些相对不稳定的组件依赖。

3.4- 稳定抽象原则

在一个软件系统中,总有些部分是不应该经常发生变更的。这些部分通常用于表现该系统的高阶架构设计及一些策略相关的高阶决策。我们不想让这些业务决策和架构设计经常发生变更,因此这些代表了系统高阶策略的组件应该被放到稳定组件(I=0)中,而不稳定的组件(I=1)中应该只包含那些我们想要快速和方便修改的部分
 
 
 
 然而,如果我们将高阶策略放入稳定组件中,那么用于描述那些策略的源代码就很难被修改了。这可能会导致整个系统的架构设计难于被修改。如何才能让一个无限稳定的组件(I=0)接受变更呢?开闭原则(OCP)为我们提供了答案。这个原则告诉我们:创造一个足够灵活、能够被扩展,而且不需要修改的类是可能的,而这正是我们所需要的。哪一种类符合这个原则呢?答案是抽象类
 
 稳定抽象原则(SAP)为组件的稳定性与它的抽象化程度建立了一种关联。一方面,该原则要求稳定的组件同时应该是抽象的,这样它的稳定性就不会影响到扩展性。另一方面,该原则也要求一个不稳定的组件应该包含具体的实现代码,这样它的稳定性就可以通过具体的代码被轻易修改。
 
 
 因此,如果一个组件想要成为稳定组件,那么它就应该由接口和抽象类组成,以便将来做扩展。如此,这些既稳定又便于扩展的组件可以被组合成既灵活又不会受到过度限制的架构。
 将 SAP 与 SDP 这两个原则结合起来,就等于组件层次上的 DIP。因为 SDP 要求的是让依赖关系指向更稳定的方向,而 SAP 则告诉我们稳定性本身就隐含了对抽象化的要求,即依赖关系应该指向更抽象的方向

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值