再上一篇:9 .2 模块化程序结构图
上一篇:9 .3 模块的独立程度
主页
下一篇:9 .3 .2 模块耦合
再下一篇:9 .4 模块化程序设计步骤
文章列表

9 .3 .1 模块内聚

《程序设计基础》(基于C语言讲解) 石光华 编著 —北京: 清华大学出版社

在建立模块时,程序设计员可采用检查模块内聚度的方法,去掉模块设计中的不确定性。内聚度是衡量模块内聚力的一种手段,它标志了一个模块内部各个元素或语句之间彼此结合的紧密程度。模块内部元素之间联系得越紧密,模块的内聚度就越高。高内聚度的模块被认为是组织结构良好的模块。

EdwardYourdon和Larry Constantine提出了7种类型的模块内聚,并按照内聚力的强弱进行排序。具体如图9-3所示。

130 程序设计基础

图9-3 模块内聚图

1 .偶然内聚

偶然内聚是模块内聚度中最弱的一种类型。偶然内聚一般指的是模块内部的各个元

素之间没有确切联系,或即使有联系,联系也是很松散的情况。例如,编写完一个程序之

后,发现一组语句在两处或多处出现,于是把这些语句构成一个模块以节省内存,这样就

构成了偶然内聚的模块,在这种情况下很难准确定义模块的功能。

2 .逻辑内聚

逻辑内聚是指模块内部的各个元素之间按照完成的某类任务组合在一起的情况。换

句话说,模块完成的任务在逻辑上属于相同或相似的一类,即它们都做同样的事情。

逻辑内聚模块比偶然内聚模块的功能更强一些,这主要是由于逻辑内聚模块的各元

素之间至少存在某种程度的联系。然而,逻辑内聚模块经常可由许多更小的、独立的模块

构成,模块应该独立存在而不应按照某种关系组合在一起。通常,当逻辑内聚模块为被调

模块时,只有模块内的一小部分元素将被执行。

【例9-1】 构成名为add_all_score的模块,该模块对3个不同的班级进行加分操作。

这种情况下,主调模块将通过传递不同的参数来告诉被调模块应该对3 个班级中的哪一

个进行加分操作。

int add_all_score(int key)

{

switch(key)

{

case 1:

add_score1();

break;

第9章 模块化程序设计 131

case 2:

add_score2();

break;

case 3:

add_score3();

break;

}

}

模块add_all_score()由int key决定为哪一个班级的成绩加分。

3 .时间内聚

时间内聚是指模块内部的各个元素之间按照时间关系组合在一起的情况,即模块包含的任务必须在同一段时间内执行的情况。典型的实例是模块初始化操作和模块终止操作,把这些元素放置在一起主要是由于它们都在程序开始或结束时执行一定的初始化和收尾工作。

时间内聚模块可看成是与时间相关联的逻辑内聚模块,但它比逻辑内聚模块的功能更强一些,因为它是与时间相关联的模块,在模块调用的同时执行模块中的大部分元素。但通常这种情况下模块中的元素并不都执行同样的功能。

【例9-2】 时间内聚模块。

(1) 开始的模块

void mybegin()

{

printf(″game begin .\n″);

printf(″wellcome ! \n″);

read_all_data();

}

(2) 结束的模块

void myend()

{

printf(″game end\n″;);

printf(″good bye ! \n″);

clear_all_data();

}

132 程序设计基础

4 .过程内聚

过程内聚是指模块内部的各处理元素是相关的,而且按照特定过程执行的情况。换

句话说,模块内部的各个元素为达到程序要求的目标,将按特定的次序执行。因此,模块

包含的各处理元素主要与程序的执行过程有关,而与程序功能无关。

过程内聚模块的典型实例是程序的主模块。主模块中的各个元素按照特定的程序执

行顺序组合在一起。

过程内聚模块的弱点在于它们超越了模块的功能界限。也就是说,过程内聚模块可

能包含某一级模块功能中的部分功能,但同时还可能包含更低层模块中的多个功能。

【例9-3】 过程内聚模块。

void main()

{

int key=0;

while (1)

{

scanf(″%d″,&key);

mybegin();

add_all_score(key);

myend();

if (key= = - 1)

break;

}

}

5 .通信内聚

通信内聚是指模块内部的各处理元素都使用相同的输入数据和(或)产生同样的输出

数据的情况。通信内聚模块在事务应用中最常见,这主要是由于在事务性程序中处理的

数据之间有一定的紧密联系。通信内聚模块由于数据之间是相关联的,因此比过程内聚

模块在功能上的联系更紧密。

【例9-4】 在下面的程序中找出处理相同的输入数据iage[SIZE]的最大和最小年龄

的模块。

#include < stdio .h>

#define SIZE 5

第9章 模块化程序设计 133

void main()

{

int iindex=0;

int iage[SIZE] ={0};

int imaxage=0,iminage=0;

for(iindex=0;iindex

{

printf(″Please input age :\n″);

scanf(″%d″,&iage[iindex]);

}

imaxage=iage[0]; / *必须保证从数组的第1个元素开始找*/

for(iindex=0;iindex

{

if (imax age

imaxage=iage[iindex];

}

printf(″MAX age is %d″,imaxage);

iminage=iage[0]; / *必须保证从数组的第1个元素开始找*/

for(iindex=0;iindex

{

if (iminage>iage[iindex])

iminage=iage[iindex];

}

printf(″MIN age is %d″,iminage);

}

6 .顺序内聚

顺序内聚是指模块内各个元素依赖于前面元素的处理。换句话说,模块各处理元素的功能密切相关且顺序执行。例如,某个元素的输出数据可能作为下一个元素的输入数据。因此,与装配线有些相似,顺序内聚模块是指对数据进行连续转换的一系列顺序执行的处理步骤。

顺序内聚模块由于后面元素依赖于前面元素的处理,因此比通信内聚模块功能联系得更紧密一些。其弱点在于,模块可能要完成多个功能或部分功能,而使模块功能不单一。

134 程序设计基础

【例9-5】 顺序内聚模块。

voidfun()

{

read_all_scores();

change_all_scores();

count_for_average();

}

7 .功能内聚

功能内聚是指模块内所有元素为完成某一特定任务而组合在一起的情况。模块可以

很容易命名,采用一个简单动词后跟两个词的宾语形式进行命名即可。与数学计算有关

的模块是功能内聚模块的很好的实例,因为这些模块的所有元素构成该计算的一个完整

部分。

【例9-6】 功能内聚my_abs模块。

int my_abs(int ino)

{

int iresult=0;

if (ino > =0)

iresult=ino;

else

iresult= - ino;

return iresult;

}

在考虑内聚形式时,需要注意如下。

程序设计人员在设计程序结构时,要尽量采用具有单一、特定功能的模块。如果按功

能内聚模块进行设计,那么模块将更独立,也更容易阅读和理解,与内聚度较低的模块相

比它更易于维护。

在具体应用中,要确保程序中的每个模块都是功能内聚模块不太容易。某个模块可

能含有较低层次的内聚形式,甚至含有几种内聚的组合形式。但对程序设计人员来说,应

能够辨别各种内聚形式,并能证明在特定情况下内聚程度较低模块的正确性,这点尤为

重要。

程序设计人员进行程序设计时,首要考虑的必须是尽量采用易于理解和修改的模块

来组织程序。模块的内聚程度越高,就越有可能达到这一目的。

第9章 模块化程序设计 135