对于子程序而言,内聚性是指子程序中各种操作之间联系的紧密程序。什么样才是高质量的子程序,其中一点就是高内聚性,其目标是让每一个子程序只把一件事做好,不再做任何其他事情。
关于内聚的讨论一般会涉及到内聚性的几个层次。理解一些概念要比记住一些特定的术语更重要。这些概念可以帮助你思考如何让子程序尽可能地内聚。
功能性内聚 是最强也是最好的一种内聚性,也就是说让一个子程序仅执行一项操作。例如:getCustomerName()、EraseFile()、sin()以及ageFromBirthdate()这样的子程序都是高度内聚的。当然,以这种方式来评估内聚性,前提是子程序所有执行的操作与名字相符——如果它还做了其他的操作,那么它就不够内聚,同时其命名也有问题。
除此之外,还有其他一些种类的内聚性人们却通常认为是不够理想的。
顺序内聚 是指在子程序内包含有需要按特定的顺序执行的操作,这些步骤需要共享数据,而且只有在全部执行完毕后才完成了一项完整的功能。
举一个顺序上的内聚性的例子,假设某个子程序需要按照给定出生日期来计算出员工的年龄和退休时间。如果子程序先计算员工的年龄,再根据他的年龄来计算退休时间,那么它就具有顺序的内聚性。而如果子程序先计算员工的年龄,然后再重新计算他的退休时间,两次计算只是碰巧使用了相同的出生日期,那么这个子程序就只具有通信上的内聚性。
那么该怎样设计具有功能上的内聚性的子程序呢?你可以创建两个不同的子程序,它们能根据给定的生日分别计算员工的年龄和退休时间。其中,计算退休时间的子程序可以调用计算年龄的子程序。这样两者就都具有功能上的内聚性了。而其他的子程序则可以调用二者之一或全部。
通信内聚 是指一个子程序中不同的操作使用同样的数据,但不存在其他任何联系。例如某个子程序先根据传给它的汇总数据打印一份汇总报表,然后再把这些汇总数据重新初始化,那么这个子程序就具有通信上的内聚性:因为这两项操作只是因为使用了相同的数据才彼此产生联系。
要改善这个子程序的内聚性,应该让重新初始化汇总数据的操作尽可能靠近创建汇总数据的地方,而不是放在打印报表的子程序里。应该把这些子程序进一步拆分成几个独立的子程序:一个负责打印报表,一个负责在靠近创建或修改数据的代码的地方重新初始化数据。然后在原本调用那个具有通信内聚性的子程序的更高的子程序中调用这两个子程序。
临时内聚 是指含有一些因为需要同时执行才放到一起的操作的子程序。典型的例子有:startUp()、completeNetEmployee()、shutdown()等。有些人认为临时内聚性是不可取的,因为它们有时与不良的编程实践相关——比如说在startUp()子程序里塞进一大堆互不相关的代码等。
为避免这个问题,可以把临时性的子程序看做一系列事件的组织者。前面提到的startUp()子程序可能需要读取配置文件、初始化临时文件、创建表结构,再启动画面。要想使它最有效,应该让原来那具有临时内聚性的子程序去调用其他的子程序,由这些子程序来完成特定的操作,而不是由它直接执行所有的操作。
这个例子提出这样一个问题,即如何选择一个能够恰当的抽象层次上描述子程序的名字。你可能决定把一个子程序命名为readConfigFileInitScratchFileEct(),它可以暗示该子程序只是巧合的内聚性。而如果你把命名为startUp(),那么很明显,这个子程序就只具有一个功能,且具有功能上的内聚性。
一般来说,其他类型的内聚性都是不可取的。它们都会导致代码组织混乱、难于调查试、不便修改。如果一个子程序具有不良的内聚性,那最好还是花功夫重新编写,使其具有更好的内聚性,而不是再花精力精确地诊断问题所在了。因此,知道应该避免什么是非常有用的,下面就给出一些不可取的内聚性。
过程内聚 是指一个子程序中的操作是按特定的顺序进行的。一个例子是依次获取员工的姓名、住址和电话号码的子程序。这些操作执行的顺序之所以重要,只是因为它和用户屏幕提示而输入数据的顺序想一致。另一个子程序用来获取员工的其他数据。这段程序也具有过程上的内聚性,因为它把一组操作赋以特定的顺序,而这些操作并不需要为了除此这外的任何原因而彼此关联。
为了得到更好的内聚性,可以把不同的操作纳入各自的子程序中。让调用方的子程序具有单一而完整的功能:getEmployee()就比getFirstPartOfEmployeeData()更为可取。你可能还需要修改用来读取其余的子程序。为了让所有的子程序都具有功能上的内聚性,对两个或更多的原有子程序进行修改是很常用见的。
逻辑内聚 是指若干操作被放入同一个子程序中,通过传入的控制标志选择执行其中的一项操作。之所以称之为逻辑上的内聚性,是因为子程序的控制流或所谓“逻辑”是将这些操作放到一起的唯一原因——它们都被包在一个很大的if语句或case语句中,而不是因为各项操作之间有任何逻辑关联。认为是逻辑上的内聚性的标志性属性就是各项操作之间的关联,因此,似乎更应该称其为“缺乏逻辑的内聚性”。
这方面的一个例子是名为inputAll()子程序,它根据传入的控制标志决定是输入客户姓名、住址还是其他数据。类似例子还有computeAll()、editAll()、printAll()和saveAll()。这种子程序的主要问题是你不该通过传入控制标志来控制另一个子程序的处理方式。相比之下,让三个程序分别完成不同的操作,要比用一个“根据传入的控制标志选择三项不同的操作之一”的子程序要清晰得多。如果操作中含有一些相同代码或共用了数据,那么应该把那些代码移入一个低层子程序中,这些子程序也应该包裹在一个类中。
如果子程序里的代码仅由一系列的if语句或者case语句,以及调用其他子程序的语句组成,那么创建这样一个具有逻辑内聚的子程序通过也是可以的。在这种情况下,如果子程序唯一的功能就是发布各种命令,其自身并不做任何处理,这通常也是不错的设计。这类子程序的技术术语便是“事件处理器”。
巧合内聚 是指子程序中的各种操作之间没有任何可以看到的关联。它也可称为“无内聚”或“混乱内聚”。很难从巧合内聚转变成任何一类更好的内聚——通常你需要深入地重新设计和重新实现。
以上,感谢《代码大全》作者对其精辟的解析。使我顿时感悟,不再停留在对概念的理解上,以一种更顺畅的思维去分析问题,设计结构。从上面的分析,我时刻很强烈感觉重构的影子。从头到尾,重构的思想一直在脑中不停的转动,例如:提炼方法、搬移方法、引入外加函数、重命名方法都是上面提及的一些思想。
作者最后一句话说道:编写功能内聚的子程序几乎总是可能的,因此把注意集中于功能内聚,从而得到最大的收获。
分享到:
相关推荐
通过理解并实践高内聚与低耦合的原则以及相关的接口设计原则,可以显著提高软件系统的质量和可维护性。这些概念不仅适用于传统的面向对象编程,同样也适用于现代的微服务架构和其他软件开发模型。
- **功能内聚**:子程序应专注于一项具体任务,做到高内聚,确保每个子程序只做一件事并做好。 - **松耦合**:子程序间的交互应当简洁、明确,减少不必要的依赖关系。 2. 防错性编程 - **断言**:利用断言来验证...
### 软件工程中的高耦合与低内聚 在软件工程领域,"高耦合、低内聚"是一个非常重要的概念。该概念强调了软件设计时各个组成部分之间的关系和交互方式。为了更好地理解这一概念,我们首先需要了解一些基本的定义。 ...
2. 模块功能应单一清晰,内聚度高,独立性强,避免使用无条件转移语句破坏结构完整性。 3. 控制耦合应简单,每个模块只有一个入口和一个出口,简化调试过程。 4. 数据耦合要尽量少,减少模块间的数据交换,以降低...
在实践中,设计和实现具有高内聚性和低耦合性的模块和子程序是提升软件质量的关键。通过定义清晰的接口,确保模块的独立性,从而实现“黑盒子”效果,使每个模块或子程序都能独立完成特定的任务,这将极大提升软件的...
本章详细介绍了建立子程序的具体步骤,为开发者提供了一个系统的方法来创建高质量的子程序。 #### 第五章:高质量子程序特点 - **5.1 生成子程序的原因** 创建子程序的主要原因是为了提高代码的可读性、可维护...
A、偶然内聚 B、逻辑内聚 C、时间内聚 D、过程内聚 3、开发软件所需高成本和产品的低质量之间有着尖锐的矛盾,这种现象称( C ) A. 软件工程 B. 软件周期 C. 软件危机 D. 软件产生 4、软件详细设计的主要任务是确定每...
24. **内聚性**:第33题中,功能性内聚是最强的内聚类型,意味着模块内部所有元素都紧密关联,共同完成单一功能。 25. **Jackson设计方法**:第34题介绍了面向数据结构的Jackson设计方法,强调根据数据结构设计程序...
本PPT文档详细阐述了模块独立性及其不同类型的内聚和耦合,这些都是衡量模块质量的关键指标。 首先,内聚是衡量模块内部成分间相关性的度量。根据描述,主要有以下几种内聚类型: 1. 偶然型内聚:模块中的成分彼此...
根据内聚度的不同,可以将其分为七种类型,从低到高分别为偶然内聚、逻辑内聚、顺序内聚、通信内聚、过程内聚、功能内聚和顺序内聚。 综上所述,软件质量评价涵盖了软件的各个方面,从用户需求到开发人员的角度,从...
- **低耦合高内聚**:模块间的关系尽量简单,每个模块内部保持高度集中。 - **可扩展性**:设计应允许未来功能的添加和修改。 - **可维护性**:易于理解、修改和调试的代码结构。 - **效率**:考虑运行时间和...
模块独立性是衡量模块质量的重要指标,通过内聚度(模块内部组件的紧密程度)和耦合度(模块间的关系)来评估,高内聚、低耦合的模块具有更好的独立性。 内聚度通常分为七类,从弱到强依次为偶然内聚、逻辑内聚、...
总之,总体设计是一个系统性、逻辑性强的过程,涉及多个方面,包括方案的生成、评估、选择,以及模块化、抽象、信息隐藏、局部化、耦合和内聚等原则的应用,所有这些都是为了构建高质量、易于维护的软件系统。
- 类型包括偶然内聚、逻辑内聚、时间内聚、过程内聚、通信内聚、顺序内聚和功能内聚。 8. **可行性研究的步骤**: - 重审项目规模和目标。 - 分析现有系统。 - 构建高层逻辑模型。 - 重新定义问题。 - 探索...
该文凭论文的目的是开发一种用于量化封装级内聚和耦合的方法,以便提出解决方案以提高面向对象系统的设计质量。 封装中类的一致性一旦促进了封装,便是可取的。 它显示了每个程序包中的功能多么强大。 结构良好的...
结构化程序设计是一种编程方法论,它强调通过分解复杂问题,使用简单的结构构建程序,以提高代码的可读性、可维护性和可测试性。...这种设计理念对于培养良好的编程习惯和编写高质量代码至关重要。
- **使用注意事项**:本教材并不系统地讲解C/C++高级语言的所有细节,而是侧重于教授编写高质量程序的关键点。对于具体语言特性的深入了解,建议参考专门的语言教程书籍。 #### 如何设计编写高质量的函数 - **编写...