过程则着重描述各个模块的处理细节。 软件过程必须提供精确的处理说明,包括事件的顺序、正确的判定点、重复的操作直至 数据的组织和结构等等。程序结构与软件过程是有关系的。对每个模块的处理必须指明该模 块所在的上下级环境。软件过程遵从程序结构的主从关系,因此它也是层次化的。 (8)信息隐蔽 如何分解一个软件才能得到最佳的模块组合?为了明确怎样去做,需要了解什么是“信 息隐蔽”。由 parnas提倡的信息隐蔽是指,每个模块的实现细节对于其它模块来说是隐蔽的 就是说,模块中所包含的信息(包括数据和过程)不允许其它不需要这些信息的模块使用。 通常有效的模块化可以通过定义一组独立的模块来实现,这些模块相互间的通信仅使用 对于实现软件功能来说是必要的信息。通过抽象,帮助我们确定组成软件的过程(或信息) 实体,通过信息隐蔽,则可定义和实施对模块的过程细节和局部数据结构的存取限制 由于一个软件系统在整个软件生存期内要经过多次修改,所以在划分模块时要采取措 施,使得大多数过程和数据对软件的其它部分是隐蔽的。这样,在将来修改软件时偶然引入 错误所造成的影响就可以局限在一个或几个模块内部,不致波及到软件的其它部分 3.软件体系结构 软件体系结构的三要素是程序构件(模块)的层次结构、构件之间交互的方式,以及数 据的结构。软件设计的一个目标是建立软件的体系结构表示。将这个表示当作一个框架,从 事更详细的设计活动。Shaw和 Garlan提出了在软件体系结构设计中应保持的几个性质: 结构:体系结构设计应当定义系统的构件,以及这些构件打包的方式和相互交互的 方式。如将对象打包以封装数据和操纵数据的处理,并通过相关操作的调用来进行交互 附属的功能:体系结构设计应当描述设计出来的体系结构如何实现对功能、性能 可靠性、安全性、适应性,以及其它的系统需求 可复用:体系结构设计应当描述为一种可复用的模式,以便在以后类似的系统族的 设计中使用它们。此外,设计应能复用体系结构中的构造块。 表41列出可能的软件构件,表42列出可能的构件间的连接方式。 表41软件构件分类 构件 寺点和示例 纯计算构件具有简单的输入/输出关系,没有运行状态的变化。例如,数值计算、过滤器( Filters) 转换器(Tra 存储枃件存放共享的、永久性的、结枃化的数据。例如,数据库、文件、符号表、超文本等。 管理构件执行的操作与运行状态紧密耦合。例如,抽象数据类型(ADT)、面向对象系统中的对 象、许多服务器( Servers)等。 控制构件管理其它构件运行的时间、时机及次序。例如,调度器、同步器等 链接构件在实体之间传递信息。例如,通信机制、用户界面等 表42构件之间的连接方式 寺点与示例 过程调用在某一个执行路径中传递执行指针。例如,普通过程调用(同一个命名空间)、远程过 程调用(不同的命名空间) 数据流 相互独立的处理通过数据流进行交互,在得到数据的同时被赋予控制权限。例如,UNIX 系统中的管道( pIpes)。 间接激活处理是因事件的发生而激活的,在处理之间没有直接的交互。例如,事件驱动系统、自
6 过程则着重描述各个模块的处理细节。 软件过程必须提供精确的处理说明,包括事件的顺序、正确的判定点、重复的操作直至 数据的组织和结构等等。程序结构与软件过程是有关系的。对每个模块的处理必须指明该模 块所在的上下级环境。软件过程遵从程序结构的主从关系,因此它也是层次化的。 (8) 信息隐蔽 如何分解一个软件才能得到最佳的模块组合?为了明确怎样去做,需要了解什么是“信 息隐蔽”。由 parnas 提倡的信息隐蔽是指,每个模块的实现细节对于其它模块来说是隐蔽的。 就是说,模块中所包含的信息(包括数据和过程)不允许其它不需要这些信息的模块使用。 通常有效的模块化可以通过定义一组独立的模块来实现,这些模块相互间的通信仅使用 对于实现软件功能来说是必要的信息。通过抽象,帮助我们确定组成软件的过程(或信息) 实体,通过信息隐蔽,则可定义和实施对模块的过程细节和局部数据结构的存取限制。 由于一个软件系统在整个软件生存期内要经过多次修改,所以在划分模块时要采取措 施,使得大多数过程和数据对软件的其它部分是隐蔽的。这样,在将来修改软件时偶然引入 错误所造成的影响就可以局限在一个或几个模块内部,不致波及到软件的其它部分。 3. 软件体系结构 软件体系结构的三要素是程序构件(模块)的层次结构、构件之间交互的方式,以及数 据的结构。软件设计的一个目标是建立软件的体系结构表示。将这个表示当作一个框架,从 事更详细的设计活动。Shaw 和 Garlan 提出了在软件体系结构设计中应保持的几个性质: ▪ 结构 :体系结构设计应当定义系统的构件,以及这些构件打包的方式和相互交互的 方式。如将对象打包以封装数据和操纵数据的处理,并通过相关操作的调用来进行交互。 ▪ 附属的功能 :体系结构设计应当描述设计出来的体系结构如何实现对功能、性能、 可靠性、安全性、适应性,以及其它的系统需求。 ▪ 可复用 :体系结构设计应当描述为一种可复用的模式,以便在以后类似的系统族的 设计中使用它们。此外,设计应能复用体系结构中的构造块。 表 4.1 列出可能的软件构件,表 4.2 列出可能的构件间的连接方式。 表 4.1 软件构件分类 构 件 特 点 和 示 例 纯计算构件 具有简单的输入∕输出关系,没有运行状态的变化。例如,数值计算、过滤器(Filters)、 转换器(Transformers)等。 存储构件 存放共享的、永久性的、结构化的数据。例如,数据库、文件、符号表、超文本等。 管理构件 执行的操作与运行状态紧密耦合。例如,抽象数据类型(ADT)、面向对象系统中的对 象、许多服务器(Servers)等。 控制构件 管理其它构件运行的时间、时机及次序。例如,调度器、同步器等。 链接构件 在实体之间传递信息。例如,通信机制、用户界面等。 表 4.2 构件之间的连接方式 连 接 特 点 与 示 例 过程调用 在某一个执行路径中传递执行指针。例如,普通过程调用(同一个命名空间)、远程过 程调用(不同的命名空间)。 数据流 相互独立的处理通过数据流进行交互,在得到数据的同时被赋予控制权限。例如,UNIX 系统中的管道(pipes)。 间接激活 处理是因事件的发生而激活的,在处理之间没有直接的交互。例如,事件驱动系统、自
动垃圾回收等 消息传递相互独立的处理之间有明确的交互,通过显式的离散方式的数据传递。这种传递可以是 同步的,也可以是异步的。例如,TCP/IP。 共享数据构件们通过同一个数据空间进行并发的操作。例如,多用户数据库、数据黑板系统 软件系统的体系结构经历了一个由低级到高级的发展过程。其间出现过下列体系结构 (1)数据流系统 批处理 管道及过滤器 这种结构中的每一个组成成份都有一套输入和输出数据,都依输入数据一处理一输出结 果的方式工作。进行数据变换的构件叫做过滤器,把数据从一个过滤器的输出导入到另一个 过滤器的输入,就叫做管道。在这种系统中,各个过滤器必须是相互独立的,每一个过滤器 对它的上游或下游的过滤器的情况是不知道的,也不能做任何假设。如果要求最终的输出结 果与各个过滤器的执行次序相关,就是一个数据流方式的体系结构。这种结构的优点是:数 据流程设计明确,直接支持复用,系统容易维护和升级,可以进行某些性能分析(如流量、 死锁等),容易支持并行计算。缺点是:容易导致把系统变成为简单的批处理作业。每一个过 滤器都要考虑相似的数据检验和处理,不能很好地支持交互式操作和反馈。对数据的格式不 能做过多的约定,使得每个过滤器的实现会更复杂。 (2)调用一返回系统 主程序/子程序 层次结构 在层次结构中,每一层都只与上下相邻的两层通信。每一层在利用下层基础服务的条件 下,为上层提供服务。最典型的例子就是各种虚拟机、X- window以及 OSL-ISO的7层网络 协议。这种结构的优点是:提供逐步抽象的编程支持,支持复用及系统升级。缺点是:不是 所有的系统都适合于建成层次结构,不能提供最佳性能。 面向对象的系统 在这种系统中,数据和其相关的基本操作被封装在一起。系统的构件是对象。对象具有 诸如封装、隐蔽、继承等良好的特性。对象必须自己维护其数据的一致性。这种结构的优点 是:将具体的实现部分隐蔽在对象中,使得代码之间的独立性很好,有利于将复杂的系统分 解为相互操纵的子任务。缺点是:对象间进行一般的调用时必须知道对方的标识。如果一个 对象的标识发生变化,所有显式调用这个对象操作的地方都要修改。对象之间的同步等还缺 乏现成的机制。 (3)独立构件系统 进程间通信 事件驱动 这种结构的特点是事件的发出者不必知道,也不应假设对该事件的具体处理过程。它的 优点是:提供了强大的可复用性支持。系统的重配置也很容易。缺点是:软件系统中的构件 在很大程度上依靠操作系统的调用。如果一个事件的处理需要多个进程处理,活动进程的激 活次序是不能保证的。经过事件传递数据也较受限制。事件处理中的逻辑处理实际上带有时 态性质,与一般的逻辑处理不一样。 (4)虚拟机 解释器 解释器的目的是实现一个虚拟机。这是一类比较复杂的体系结构,但是,如果进行结构 分析的话,就会发现看似不同的系统有着十分相似的结构
7 动垃圾回收等。 消息传递 相互独立的处理之间有明确的交互,通过显式的离散方式的数据传递。这种传递可以是 同步的,也可以是异步的。例如,TCP∕IP。 共享数据 构件们通过同一个数据空间进行并发的操作。例如,多用户数据库、数据黑板系统。 软件系统的体系结构经历了一个由低级到高级的发展过程。其间出现过下列体系结构。 (1) 数据流系统 ▪ 批处理 ▪ 管道及过滤器 这种结构中的每一个组成成份都有一套输入和输出数据,都依输入数据―处理―输出结 果的方式工作。进行数据变换的构件叫做过滤器,把数据从一个过滤器的输出导入到另一个 过滤器的输入,就叫做管道。在这种系统中,各个过滤器必须是相互独立的,每一个过滤器 对它的上游或下游的过滤器的情况是不知道的,也不能做任何假设。如果要求最终的输出结 果与各个过滤器的执行次序相关,就是一个数据流方式的体系结构。这种结构的优点是:数 据流程设计明确,直接支持复用,系统容易维护和升级,可以进行某些性能分析(如流量、 死锁等),容易支持并行计算。缺点是:容易导致把系统变成为简单的批处理作业。每一个过 滤器都要考虑相似的数据检验和处理,不能很好地支持交互式操作和反馈。对数据的格式不 能做过多的约定,使得每个过滤器的实现会更复杂。 (2) 调用―返回系统 ▪ 主程序∕子程序 ▪ 层次结构 在层次结构中,每一层都只与上下相邻的两层通信。每一层在利用下层基础服务的条件 下,为上层提供服务。最典型的例子就是各种虚拟机、X-window 以及 OSI-ISO 的 7 层网络 协议。这种结构的优点是:提供逐步抽象的编程支持,支持复用及系统升级。缺点是:不是 所有的系统都适合于建成层次结构,不能提供最佳性能。 ▪ 面向对象的系统 在这种系统中,数据和其相关的基本操作被封装在一起。系统的构件是对象。对象具有 诸如封装、隐蔽、继承等良好的特性。对象必须自己维护其数据的一致性。这种结构的优点 是:将具体的实现部分隐蔽在对象中,使得代码之间的独立性很好,有利于将复杂的系统分 解为相互操纵的子任务。缺点是:对象间进行一般的调用时必须知道对方的标识。如果一个 对象的标识发生变化,所有显式调用这个对象操作的地方都要修改。对象之间的同步等还缺 乏现成的机制。 (3) 独立构件系统 ▪ 进程间通信 ▪ 事件驱动 这种结构的特点是事件的发出者不必知道,也不应假设对该事件的具体处理过程。它的 优点是:提供了强大的可复用性支持。系统的重配置也很容易。缺点是:软件系统中的构件 在很大程度上依靠操作系统的调用。如果一个事件的处理需要多个进程处理,活动进程的激 活次序是不能保证的。经过事件传递数据也较受限制。事件处理中的逻辑处理实际上带有时 态性质,与一般的逻辑处理不一样。 (4) 虚拟机 ▪ 解释器 解释器的目的是实现一个虚拟机。这是一类比较复杂的体系结构,但是,如果进行结构 分析的话,就会发现看似不同的系统有着十分相似的结构
·推理系统 过程控制 这种结构要比较外界变量与目标常数的差异,经过控制策略的计算,反馈信号,控制需 要监测和控制的过程 (5)数据为中心的系统 数据库 超文本系统 数据黑板系统 这种结构的特点是:有两种构件:一是被共享的结构化数据,保存了所有的运行状态; 二是所有访问这些数据的独立的进程。如果是因为输入的数据而引起对共享数据的操作,那 么这种控制策略下的体系结构就叫做数据库。如果是由共享数据的当前状态触发相应的处理 进程,那么这种体系结构就叫做数据黑板。许多表面上看起来是其它种类的体系结构,可以 同时归入这种体系结构。 (6)其它 分布式处理的系统 特定领域的软件体系结构 (7)演进与综合 一般来讲,一个新系统的原型最开始出现时,往往以批处理方式进行组合;在进一步的 应用分析过程中,将逐步对交互控制方式、实时的反馈、集成化等方面提出需求,因而系统 将逐步向以数据为中心的系统过渡,中间还可能会经过一种或几种演化形态。 4.有效的模块设计 模块化方法带来了许多好处。一方面,模块化设计降低了系统的复杂性,使得系统容易 修改;另一方面,推动了系统各个部分的并行开发,从而提高了软件的生产效率 (1)模块 模块又称构件,在传统的方法中指用一个名字就可调用的一段程序。类似于高级语言中 的过程、函数等。它一般具有如下三个基本属性: 功能:即指该模块实现什么功能,做什么事情。 逻辑:即描述模块内部怎么做。 状态:即该模块使用时的环境和条件 在描述一个模块时,还必须按模块的外部特性与内部特性分别描述。模块的外部特性是 指模块的模块名、参数表、以及给程序以至整个系统造成的影响。而模块的内部特性则是指 完成其功能的程序代码和仅供该模块内部使用的数据 对于模块的外部环境(例如需要调用这个模块的上级模块)来说,只需要了解这个模块 的外部特性足够了,不必了解它的内部特性。而软件设计阶段,通常是先确定模块的外部特 性,然后再确定它的内部特性。 (2)模块独立性 所谓模块的独立性,是指软件系统中每个模块只涉及软件要求的具体的子功能,而和软 件系统中其它的模块的接口是简单的。例如,若一个模块只具有单一的功能且与其它模块没 有太多的联系,那么,我们则称此模块具有模块独立性 般采用两个准则度量模块独立性。即模块间的耦合和模块的内聚。 (3)内聚性 内聚是模块功能强度(一个模块内部各个元素彼此结合的紧密程度)的度量。一个内聚 程度高的模块(在理想情况下)应当只做一件事。一般模块的内聚性分为七种类型
8 ▪ 推理系统 ▪ 过程控制 这种结构要比较外界变量与目标常数的差异,经过控制策略的计算,反馈信号,控制需 要监测和控制的过程。 (5) 数据为中心的系统 ▪ 数据库 ▪ 超文本系统 ▪ 数据黑板系统 这种结构的特点是:有两种构件:一是被共享的结构化数据,保存了所有的运行状态; 二是所有访问这些数据的独立的进程。如果是因为输入的数据而引起对共享数据的操作,那 么这种控制策略下的体系结构就叫做数据库。如果是由共享数据的当前状态触发相应的处理 进程,那么这种体系结构就叫做数据黑板。许多表面上看起来是其它种类的体系结构,可以 同时归入这种体系结构。 (6) 其它 ▪ 分布式处理的系统 ▪ 特定领域的软件体系结构 (7) 演进与综合 一般来讲,一个新系统的原型最开始出现时,往往以批处理方式进行组合;在进一步的 应用分析过程中,将逐步对交互控制方式、实时的反馈、集成化等方面提出需求,因而系统 将逐步向以数据为中心的系统过渡,中间还可能会经过一种或几种演化形态。 4. 有效的模块设计 模块化方法带来了许多好处。一方面,模块化设计降低了系统的复杂性,使得系统容易 修改; 另一方面,推动了系统各个部分的并行开发,从而提高了软件的生产效率。 (1) 模块 模块又称构件,在传统的方法中指用一个名字就可调用的一段程序。类似于高级语言中 的过程、函数等。它一般具有如下三个基本属性: ▪ 功能:即指该模块实现什么功能,做什么事情。 ▪ 逻辑:即描述模块内部怎么做。 ▪ 状态:即该模块使用时的环境和条件。 在描述一个模块时,还必须按模块的外部特性与内部特性分别描述。模块的外部特性是 指模块的模块名、参数表、以及给程序以至整个系统造成的影响。而模块的内部特性则是指 完成其功能的程序代码和仅供该模块内部使用的数据。 对于模块的外部环境(例如需要调用这个模块的上级模块)来说,只需要了解这个模块 的外部特性足够了,不必了解它的内部特性。而软件设计阶段,通常是先确定模块的外部特 性,然后再确定它的内部特性。 (2) 模块独立性 所谓模块的独立性,是指软件系统中每个模块只涉及软件要求的具体的子功能,而和软 件系统中其它的模块的接口是简单的。例如,若一个模块只具有单一的功能且与其它模块没 有太多的联系,那么,我们则称此模块具有模块独立性。 一般采用两个准则度量模块独立性。即模块间的耦合和模块的内聚。 (3) 内聚性 内聚是模块功能强度(一个模块内部各个元素彼此结合的紧密程度)的度量。一个内聚 程度高的模块(在理想情况下)应当只做一件事。一般模块的内聚性分为七种类型
高 内聚性 低 功能内聚信息内聚|通信内聚|过程内聚时间内聚逻辑内聚|巧合内聚 强 模块独立性 功能单 功能分散 在上面的关系中可以看到,位于高端的几种内聚类型最好,位于中段的几种内聚类型是 可以接受的,但位于低端的内聚类型很不好,一般不能使用。因此,人们总是希望一个模块 的内聚类型向高的方向靠。模块的内聚在系统的模块化设计中是一个关键的因素。 巧合内聚(偶然内聚):当几个模块内凑巧有一些程序段代码相同,又没有明确表现 出独立的功能,把这些代码独立出来建立的模块即为巧合内聚模块。它是内聚程度最低的模 块。缺点是模块的内容不易理解,不易修改和维护 ■逻辑内聚:这种模块把几种相关的功能组合在一起,每次被调用时,由传送给模块 的控制型参数来确定该模块应执行哪一种功能。逻辑内聚模块比巧合内聚模块的内聚程度要 高。因为它表明了各部分之间在功能上的相关关系 时间内聚(经典内聚):这种模块大多为多功能模块,但要求模块的各个功能必须在 同一时间段内执行。例如初始化模块和终止模块。时间内聚模块比逻辑内聚模块的内聚程度 又稍高一些。在一般情形下,各部分可以以任意的顺序执行,所以它的内部逻辑更简单。 过程内聚:使用流程图做 为工具设计程序的时侯,常常通过 加工记录 流程图来确定模块划分。把流程图 打印 中的某一部分划出组成模块,就得 检验结 到过程内聚模块。这类模块的内聚 获得AB数据 程度比时间内聚模块的内聚程度文件(读文件) 计算A结果 更强一些 合并)你 通信内聚:如果一个模块 文件 计算 内各功能部分都使用了相同的输 B 入数据,或产生了相同的输出数 AB数据 据,则称之为通信内聚模块。通常, A/B卡片/读卡 片文件 通信内聚模块是通过数据流图来 定义的。如图47所示。 图47通信内聚模块 信息内聚(顺序内聚):这 种模块完成多个功能,各个功能都在同一数据 查找登录删除修改 结构上操作,每一项功能有一个唯一的入口点。 例如,图48所示的模块具有4个功能,由于模块 的所有功能都是基于同一个数据结构(符号 表),因此,它是一个信息内聚的模块。 信息内聚模块可以看成是多个功能内聚模 块的组合,并且达到信息的隐蔽。即把某个数 据结构、资源或设备隐蔽在一个模块内,不为 别的模块所知晓。当把程序某些方面细节隐藏 图48信息内聚模块 在一个模块中时,就增加了模块的独立性。 功能内聚:一个模块中各个部分都是为完成一项具体功能而协同工作,紧密联系, 不可分割的。则称该模块为功能内聚模块。功能内聚模块时内聚性最强的模块
9 图 4.8 信息内聚模块 在上面的关系中可以看到,位于高端的几种内聚类型最好,位于中段的几种内聚类型是 可以接受的,但位于低端的内聚类型很不好,一般不能使用。因此,人们总是希望一个模块 的内聚类型向高的方向靠。模块的内聚在系统的模块化设计中是一个关键的因素。 ▪ 巧合内聚(偶然内聚):当几个模块内凑巧有一些程序段代码相同,又没有明确表现 出独立的功能,把这些代码独立出来建立的模块即为巧合内聚模块。它是内聚程度最低的模 块。缺点是模块的内容不易理解,不易修改和维护。 ▪ 逻辑内聚 :这种模块把几种相关的功能组合在一起,每次被调用时,由传送给模块 的控制型参数来确定该模块应执行哪一种功能。逻辑内聚模块比巧合内聚模块的内聚程度要 高。因为它表明了各部分之间在功能上的相关关系。 ▪ 时间内聚(经典内聚):这种模块大多为多功能模块,但要求模块的各个功能必须在 同一时间段内执行。例如初始化模块和终止模块。时间内聚模块比逻辑内聚模块的内聚程度 又稍高一些。在一般情形下,各部分可以以任意的顺序执行,所以它的内部逻辑更简单。 ▪ 过程内聚 :使用流程图做 为工具设计程序的时侯,常常通过 流程图来确定模块划分。把流程图 中的某一部分划出组成模块,就得 到过程内聚模块。这类模块的内聚 程度比时间内聚模块的内聚程度 更强一些。 ▪ 通信内聚 :如果一个模块 内各功能部分都使用了相同的输 入数据,或产生了相同的输出数 据,则称之为通信内聚模块。通常, 通信内聚模块是通过数据流图来 定义的。如图4.7所示。 ▪ 信息内聚(顺序内聚):这 种模块完成多个功能,各个功能都在同一数据 结构上操作,每一项功能有一个唯一的入口点。 例如,图4.8所示的模块具有4个功能,由于模块 的所有功能都是基于同一个数据结构(符号 表),因此,它是一个信息内聚的模块。 信息内聚模块可以看成是多个功能内聚模 块的组合,并且达到信息的隐蔽。即把某个数 据结构、资源或设备隐蔽在一个模块内,不为 别的模块所知晓。当把程序某些方面细节隐藏 在一个模块中时,就增加了模块的独立性。 ▪ 功能内聚 :一个模块中各个部分都是为完成一项具体功能而协同工作,紧密联系, 不可分割的。则称该模块为功能内聚模块。功能内聚模块时内聚性最强的模块。 图 4.7 通信内聚模块
(4)耦合性 耦合是模块之间的相对独立性(互相连接的紧密程度)的度量。它取决于各个模块之间 接口的复杂程度、调用模块的方式以及哪些信息通过接口。 般模块之间可能的连接方式有七种,构成耦合性的七种类型 低 耦合性 非直接耦合数据耦合标记耦合|控制耦合外部耦合公共耦合|内容耦合 强 模块独立性 弱 ■内容耦合:如果一个模块直接访问另一个模块的内部数据:或者一个模块不通过正 常入口转到另一模块内部;或者两个模块有一部分程序代码重迭:或者一个模块有多个入口, 则两个模块之间就发生了内容耦合。在内容耦合的情形,被访问模块的任何变更,或者用不 同的编译器对它再编译,都会造成程序出错。这种耦合是模块独立性最弱的耦合。 公共耦合:若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共 耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等 公共耦合的复杂程度随耦合模块的个数增加而显著增加。如图49所示,若只是两个模 块之间有公共数据环境,则公共耦合有两种情况:松散公共耦合和紧密公共耦合。只有在模 块之间共享的数据很多,且通过参数表传递不方便时,才使用公共耦合。 外部耦合:一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是 通过参数表传递该全局变量的信息,则称之为外部耦合。外部耦合引起的问题类似于公共耦 合,区别在于在外部耦合中不存在依赖于一个数据结构内部各项的物理安排。 B B ommon公共数据区 common公共数据区 (a)松散的公共耦合 (b)紧密的公共耦合 图49公共耦合 控制耦合:如果一个模块通过传送开关、标志、 A 名字等控制信息,明显地控制选择另一模块的功能,就是 Flag 控制耦合。如图4.10所示。这种耦合的实质是在单一接 口上选择多功能模块中的某项功能。因此,对被控制模块 Flag 的任何修改,都会影响控制模块。另外,控制耦合也意味 着控制模块必须知道被控制模块内部的一些逻辑关系,这 些都会降低模块的独立性 标记耦合:如果一组模块通过参数表传递记录信 息,就是标记耦合。事实上,这组模块共享了某一数据结 构的子结构,而不是简单变量。这要求这些模块都必须清 楚该记录的结构,并按结构要求对记录进行操作 图4.10控制耦合 ■数据耦合:如果一个模块访问另一个模块时,彼此之间是通过数据参数(不是控制 参数、公共数据结构或外部变量)来交换输入、输出信息的,则称这种耦合为数据耦合。数 据耦合是松散的耦合,模块之间的独立性比较强。 非直接耦合:如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块
10 图 4.10 控制耦合 (4) 耦合性 耦合是模块之间的相对独立性(互相连接的紧密程度)的度量。它取决于各个模块之间 接口的复杂程度、调用模块的方式以及哪些信息通过接口。 一般模块之间可能的连接方式有七种,构成耦合性的七种类型。 ▪ 内容耦合 :如果一个模块直接访问另一个模块的内部数据;或者一个模块不通过正 常入口转到另一模块内部;或者两个模块有一部分程序代码重迭;或者一个模块有多个入口, 则两个模块之间就发生了内容耦合。在内容耦合的情形,被访问模块的任何变更,或者用不 同的编译器对它再编译,都会造成程序出错。这种耦合是模块独立性最弱的耦合。 ▪ 公共耦合 :若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共 耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。 公共耦合的复杂程度随耦合模块的个数增加而显著增加。如图 4.9 所示,若只是两个模 块之间有公共数据环境,则公共耦合有两种情况:松散公共耦合和紧密公共耦合。只有在模 块之间共享的数据很多,且通过参数表传递不方便时,才使用公共耦合。 ▪ 外部耦合 :一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是 通过参数表传递该全局变量的信息,则称之为外部耦合。外部耦合引起的问题类似于公共耦 合,区别在于在外部耦合中不存在依赖于一个数据结构内部各项的物理安排。 图 4.9 公共耦合 ▪ 控制耦合 :如果一个模块通过传送开关、标志、 名字等控制信息,明显地控制选择另一模块的功能,就是 控制耦合。如图 4.10 所示。这种耦合的实质是在单一接 口上选择多功能模块中的某项功能。因此,对被控制模块 的任何修改,都会影响控制模块。另外,控制耦合也意味 着控制模块必须知道被控制模块内部的一些逻辑关系,这 些都会降低模块的独立性。 ▪ 标记耦合 :如果一组模块通过参数表传递记录信 息,就是标记耦合。事实上,这组模块共享了某一数据结 构的子结构,而不是简单变量。这要求这些模块都必须清 楚该记录的结构,并按结构要求对记录进行操作。 ▪ 数据耦合 :如果一个模块访问另一个模块时,彼此之间是通过数据参数(不是控制 参数、公共数据结构或外部变量)来交换输入、输出信息的,则称这种耦合为数据耦合。数 据耦合是松散的耦合,模块之间的独立性比较强。 ▪ 非直接耦合 :如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块