系列文章目录
C++高性能优化编程系列
深入理解软件架构设计系列
深入理解设计模式系列
高级C++并发线程编程
组件构建原则
- 系列文章目录
- 1、组件构建原则的定义和解读
- 1、组件
- 2、组件聚合
- 2.1、复用/发布等同原则(REP)
- 2.2 、共同闭包原则(CCP)
- 2.3、 共同复用原则(CRP)
- 2.4、组件聚合张力图
- 3、组件耦合
- 3.1、 无依赖环原则
- 3.2、 稳定依赖原则
- 3.3、 稳定抽象原则
1、组件构建原则的定义和解读
组件构建原则是指在设计和开发组件时遵循的一些基本原则。这些原则旨在确保组件具有高可用性、可维护性、可扩展性和可复用性。
大型软件系统的构建过程与建筑物修建很类似,都是由一个个小组件组成的。所以,如果说SOLID原则是用于指导我们如何将砖块砌成墙的房间的,那么组件构建原则就是用来指导我们如何将这些房间组成房子的。
接下来,我们会详细讨论软件组件是什么?它是由什么元素构成的?以及如何利用组件来构建系统?
以下是一些常见的组件构建原则:
单一职责原则(SRP):一个组件应该只有一个职责或功能。
开放封闭原则(OCP):一个组件应该对扩展开放,对修改关闭。
依赖倒置原则(DIP):一个组件应该依赖于抽象而不是具体实现。
接口隔离原则(ISP):一个组件应该只暴露必要的接口。
最小知识原则(LOD):一个组件应该只与它直接交互的组件发生耦合。
组合/聚合复用原则(CARP):一个组件应该通过组合或聚合来实现复用。
高内聚低耦合原则(LC-HC):一个组件应该内聚性高、耦合性低。
在实际开发过程中,通过遵循这些组件构建原则,可以提高组件的质量、可用性和维护性,并减少重复代码和不必要的耦合。
1、组件
组件是软件的部署单元,是整个软件系统在部署过程中可以独立完成部署的组小实体。
我们可以将多个组件链接成一个独立可执行文件,也可以将它们汇总成类似.war文件这样的部署单元,又或者,组件也可以被打包成.jar、.dll或者.exe文件,并可以可动态加载的插件形式来独立部署。但无论采用哪种部署形式,设计良好的组件都应该永远保持可独立部署的特性,这同时也意味着这些组件应该可以被单独开发。
组件化的插件式架构已经成为我们习以为常的软件构建形式了。
2、组件聚合
究竟哪些类应该被组合成一个组件呢?这是一个非常重要的设计决策,应该遵循优秀的软件工程师经验来行事。但不幸的是,很多年以来,我们对于这么重要的决策经常是根据当下面临的实际情况临时拍脑门决定的。
接下来我们会具体讨论以下三个与构建组件相关的基本原则:
- REP:复用/发布等同原则
- CCP:共同闭包原则
- CRP:共同复用原则
2.1、复用/发布等同原则(REP)
软件复用的最小粒度应等同于其发布的最小粒度。
解释:
如果想复用某个组件的话,一般就必须要求该组件的开发由某种发布流程来驱动,并且有明确的发布版本号。
如果没有设定版本号,我们就没办法保证所有被复用的组件之间能够彼此兼容。另外更重的一点是,软件开发者必须要能够知道这些组件的的发布时间,以及每次发布带来的哪些变更。
只有这样软件工程师才能在收到相关组件新版本发布的通知之后,依据该发布所变更的内容来决定是继续使用旧版本还是做些相应的升级,这是很基本的要求。因此,组件发布的过程中还必须要能够产生适当的通知和发布文档,以便让它的用户根据这些信息做出有效的升级决策。
总结:
从软件设计和架构设计的角度来看,REP原则就是指组件中的类与模块必须是彼此紧密相关的。也就是说,一个组件不能由一组毫无关联的类和模块组成,它们之间应该有一个共同的主题或者大方向。
CCP和CRP原则会从相反的角度对这个REP原则进行有力的补偿。
2.2 、共同闭包原则(CCP)
我们应该知道将那些会同时修改,并且为了相同目的而修改的类放到同一个组件中,而将不会同时修改,并且不会为了相同目的而修改的那些类放到不同的组件中。
解释:
这其实就是SRP原则在组件层面上的再度阐述。正如SRP单一职责原则中提到的一个类不应该同时存在着多个变更原因一样,CCP原则也认为一个组件不应该同时存在着多个变更原因
对于大部分应用程序来说,可维护性的重要性要远远高于可复用性。如果某个程序中的代码必须要进行某些变更,那么这些变更都最好都体现在同一组件中,而不是分布于很多个组件中,因为如果这些变更都集中在同一个组件中,我们就只需要重新部署该组件,其他组件则不需要被重新验证、重新部署了。
总而言之,CCP的主要作用就是提示我们要将所有可能会被一起修改的类集中在一处。也就是说,如果两个类紧密相关,不管是源代码层面还是抽象理念层面,永远都会一起被修改,那么它们就应该被归属为同一个组件。通过遵守这个原则,我们就可以有效地降低因软件发布、验证及部署所带来的工作压力。
另外CCP原则和OCP开闭原则也是紧密相关的,CCP讨论的就是OCP中所指的闭包。OCP原则认为一个类应该便于扩展,而抗拒修改。w由于100%的闭包是不可能的,所以我们只能战略性地选择闭包范围。在这几类的时候,我们需要根据历史经验和预测能力,尽可能地将需要被一同变更的那些点聚合在一起。
总结:
CCP原则实际上就是SRP原则的组件版。
在SRP原则的指导下,我们将会把变更原因不同的函数放入不同的类中。而CCP原则指导我们应该将变更原因不同的类放入不同的组件中。简而言之,者两个原则都可以用这句话概括:
将由于相同的原因而修改,并且需要同时修改的东西放在一起。将由于不同的原因而修改,并且不同时修改的东西分开。
2.3、 共同复用原则(CRP)
不要强迫一个组件的用户依赖他们不需要的东西。
解释:
共同复用原则(CRP)是另外一个帮助我们决策类和模块归属于哪一个组件的原则。该原则建议我们将经常共同复用的类和模块放在同一个组件中。
通常情况下,类很少被单独复用。更常见的情况是多个类同时作为某个可复用的抽象定义被共同复用。CRP原则指导我们将这些类放在同一个组件中,而在这样的组件中,我们应该预见到会存在许多相互依赖的类。
由于这种依赖关系的存在,每当被引用组件发生变更时,引用它的组件一般也需要做出相应的变更。即使它们不需要进行代码级的变更,一般也免不了需要被重新编译、验证、部署。哪怕引用组件根本不关心被引用组件中的变更,也要如此。
CRP原则指导我们:不是紧密相连的类不应该被放在同一个组件里。
总结:
CRP原则实际上就是ISP接口隔离原则的一个普适版。ISP原则是建议我们不要依赖带有不需要的函数的类,而CRP原则则是建议我们不要依赖带有不需要的类的组件。两个原则都可以用这句话概括:
不要依赖不需要的东西。
2.4、组件聚合张力图
REP和CCP原则是粘合性原则,它们会让组件变得更大,而CRP原则是排除性原则,他会尽量让组件变小。软件架构师的任务就是要在这三个原则中间进行取舍。
简而言之,只关注REP和CRP的软件架构师会发现,即便简单的变更也会同时影响到很多组件。相反,如果软件架构师过于关注CCP和REP,则会导致很多不必要的发布。
优秀的架构师应该在上述三角张力区区中定位一个最合适目前研发团队目前状态的位置,同时,也会根据时间不停停调整。例如在项目早期,CCP原则会比REP原则更重要,因为这一阶段也会根据研发速度比复用性更重要。
一般来说,一个软件项目的重心会从该三角区域的右侧开始,先期主要牺牲的是复用性,然后,随着项目的逐渐成熟,其他项目会逐渐开始对其产生依赖,项目重心就会逐渐向该三角区域的左侧滑动。换句话说,一个项目在组件结构设计上的中心是根据该项目的开发时间和成熟度不断变动的,我们对组件结构的安排主要于项目开发的进度和它被使用的方式有关,与项目本身功能的关系其实很小。
当下适用的分割方式可能明年就不再适用了。所以,组件的构成安排应随着项目重心的不同,以及研发性与复用性的不同而不断变化。
3、组件耦合
这三条原则主要关注的是组件之间的关系。在这些原则中,我们同样会面临着研发能力和逻辑设计之间的冲突。
3.1、 无依赖环原则
组件依赖关系图中不应该出现环。
3.2、 稳定依赖原则
依赖关系必须指向更稳当的方向。
3.3、 稳定抽象原则
一个组件的抽象化程度应该与其稳定性保持一致。