是什么
按照百度百科的解释,高内聚低耦合的定义是:
高内聚低耦合,是软件工程中的概念,是判断设计好坏的标准,主要是面向对象的设计,主要是看类的内聚性是否高,耦合度是否低。
当然,单纯看定义,我们并不能理解什么叫高内聚低耦合,下面我会分别解释下什么叫内聚,什么叫耦合,以及为什么要这样做。
耦合
定义
耦合是指不同的模块之间相互依赖程度的度量。高耦合(紧密耦合)是指两个模块之间存在着很强的依赖;反之低耦合(松散耦合)是指两个模块之间存在一定依赖;无耦合就是指模块之间根本没有任何联系。 上图1-1从左至右分别展示了3种耦合关系。
原因
产生耦合的主要因素有一下几点:
- 一个模块对另一个模块的引用,例如:模块A调用了模块B,模块B调用了模块C,那么ABC3者就构成了依赖关系。
- 一个模块向另一个模块传递数据,例如:模块A为了完成其功能需要模块B向其传递一组数据。
- 一个模块对另一个模块施加控制,例如:模块A给模块B传递一个控制信号,模块B在执行操作时依赖于控制信号的值。
分类
基于上面3种原因, 存在下面几种模块间耦合类型(按从强到弱依次列出):
- 内容耦合:当一个模块直接修改或操作另一个模块的数据,或者一个模块不通过正常入口转入到另一个模块时,这样的耦合被称为内容耦合。
- 公共耦合:两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。
- 控制耦合: 一个模块通过接口向另一个模块传递一个控制信号,接收信号的模块根据信号值进行适当的动作,这种耦合称为控制耦合。
- 标记耦合:若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块BC之间存在一个标记耦合。
- 数据耦合:模块之间通过参数来传递数据,则称为数据耦合。
内聚
定义
内聚是指一个模块内部各成分之间相互关联程度的一个度量。 高内聚指一个模块中各个部分之间存在着很强的依赖;低内聚是指一个模块中各个部分之间存在较少的依赖。
分类
下面是几种常见的内聚类型(按从低到高依次列出):
- 偶然内聚:一个模块的各个成分之间基本不存在任何联系,则称为偶然内聚。
例如程序中因为多处代码重复而提取出来的公共逻辑,这组逻辑彼此间没有任何的联系,这时就出现了偶然内聚。
- 这种提取模块一般没有确定的语义或者很难了解它的语义,那么当一个应用场合需要对之进行理解或者修改的时候,就会产生相当大的困难。事实上,系统中如果存在偶然内聚的模块,那么对系统进行修改所发生的错误概率就比其它类型的模块高得多。
- 逻辑内聚:几个逻辑上相关的功能被放在同一模块中,则称为逻辑内聚。例如,一个模块读取各种类型外设的输入(如磁盘、键盘等),而不管这些输入从哪里来、做什么用,因为这个模块的各种成分都是执行输入,所以,该模块是逻辑内聚。
- 时间内聚:一个模块完成功能必须在同一时间内执行(例如,初始化系统或者一组变量),但这些功能只是因为时间因素关联在一起,称为时间内聚。
- 过程内聚:一个模块内部的处理成分相关的,而且这些处理必须以特定的次序执行,称为过程内聚。
- 通信内聚:一个模块的所有成分都操作同一个数据集或者生成同一数据集,则称为通信内聚。
- 顺序内聚:一个模块的各个成分和同一功能密切相关,而且一个成分的输出作为另一成分的输入,则称为顺序内聚。
- 功能内聚:模块的所有成分对于单一的功能都是基本的,功能内聚的模块对完成其功能而言是充分必要的。
关系
内聚和耦合两者是密切相关的,同其他模块存在高耦合的模块常意味着是低内聚的,而高内聚的模块常意味着该模块同其他模块之间是低耦合的。
怎么做
在需求分析之初,为了应对软件系统/产品的需求工作所存在的三大挑战(问题空间理解、人与人之间的通信、需求的变化性),前辈们提出了一系列的软件开发方法。包括但不限于:结构化方法、面向数据结构的软件开发方法以及近年流行的面向对象方法等。
而在结构化方法设计中,人们发现,无论待建系统等数据流图时如何的复杂,一般总可以把它们分为两种基本的类型,即变换型数据流图和事务型数据流图 。
而不论是变换设计还是事务设计,
都涉及到一个共同的问题,即“基于高内聚低耦合的原理,采用一些经验性的启发式规则,对初始模块结构图进行精化,形成最终的模块结构图”。
因此人们总结出了如下一些实现模块“高内聚低耦合”的启发式规则:
- 改进软件结构,提高模块独立性。通过模块分解或合并,改进软件结构,力求降低耦合,提升内聚,提高模块独立性。
- 力求模块规模适中。一般规模越大往往复杂度越高,从而模块的耦合度越高。经验表明,一个模块的语句最好能写在一页纸上(通常不超过60行)
- 力求深度、宽度、扇入、扇出适中。
- 深度:表示其控制的层数,如果深度过大,就应该考虑是否存在一些过分简单的管理性模块,是否可以做适当的合并。
- 宽度:指同一层模块总数的最大值。一般来说,宽度越大系统越复杂。而对宽度影响最大的因素是模块的扇出。
- 扇出:指一个模块直接控制(调用)的下级模块数目。如果一个模块的扇出过大,意味着它需要控制和协调过多的下级模块,因而该模块往往具有较为复杂的语义。反之扇出过小意味着该模块功能过于几种,导致该模块具有复杂的语义。经验表明,一个典型的系统,其平均扇出通常是3或4(上限通常是5~9)
- 扇入:表明有多少个上级模块直接调用了它。扇入越大则共享该模块的上级模块数目越多,这是有好处的,但是,不能违背模块独立性原则而单纯的追求高扇入。
- 尽力使模块的作用域在其控制域之内。
- 作用域:指受该模块内一个判定所影响的所有模块的集合
- 控制域:指这个模块本身以及所有直接或间接从属于它的模块的集合。
- 尽力降低模块接口的复杂度。
- 力求模块功能可以预测。
以上就是前辈们根据经验总结,得出的实现高内聚低耦合的启发式规则,在许多场合下可以有效地改善软件结构,对提高软件质量,往往具有重要的参考价值。