6.1模块化:内聚性和耦合性
模块化设计的目标是使每个子程序都成为一个“黑盒子”,你知道进入盒子和从盒子里出来 的是什么,却不知道里边发生什么。
如果你的子程序像一个黑盒子,那么它将是高度模块 化的,其功能明确,接口简单,使用也灵活。
模块与程序其它部分间的耦合标准与子程序间的耦合标准也是类似的。模块应被设计成可 以提供一整套功能,以便程序的其它部分与它清楚地相互作用。
模块提供的功能必须是完整的,以便它的调用者们可以各取所需
在模块设计中的最重要决定之一,便是决定哪个子 程序需要对模块中数据进行直接存取。如果某个子程序仅仅是由于可以对模块中数据进行存取 的原因才留在模块中的,那么,它应该被从模块中去掉。
6.2 信息隐蔽
进行信息隐蔽的设计思想贯穿了软件开发的每一个层次,从使用命名的常量而不是使用自 由常量到子程序设计、模块设计和整个程序设计。
隐含数据结构细节的另一个好处是容易调试
应用存取子程序最后一个优点是,可以使所有对数据的存取所遵循的是一种平行的组织形 式;或者通过存取子程序、或者直接对数据进行存取,不会两者兼而有之。当然,在负责数据 的模块内部,对数据的存取都是直接的,在这种情况下失去平行性是不可避免的,这样做的目 的是不在公共场合吹脏肥皂泡。
6.2.3 常见需要隐含的信息
· 容易被改动的区域
对硬件有依赖的地方。
输入和输出
非标准语言特性
难于设计和实现的域
状态变量
数据规模限制
商业规则
预防到改动
复杂的数据
复杂的逻辑
在程序语言层次上的操作
· 复杂的数据 · 复杂的逻辑 · 在编程语言层次上的操作
6.2.4 信息隐蔽的障碍
信息过度分散
交叉依赖:一个不易察觉的信息隐蔽障碍是交叉依赖。比如模块 A 中的某一部分调用了模块 B 中的 一个子程序,而模块 B 中又有一部分调用了模块 A 中的子程序。应避免这种交叉依赖现象。
误把模块数据当成全局数据
误认为会损失性能
6.3 建立模块的理由
从某种意义来说,模块并不是人们的目标,它只是数据及对数据所进行的操作的集合,并且支 持面向对象的概念——抽象和封装
以下是一些适合使用模块的域:
用户接口
对硬件有依赖的区域
输入与输出
操作系统依赖部分
数据管理
真实目标与抽象数据类型
可再使用的代码
可能发生变动的相互联系的操作
互相联系的操作:应把互相联系的操作放到一起。在绝大多数情况下,都可以发现 把看起来互相联系的子程序和数据放在一起的更强的组织原则
6.4 任何语言中实现模块
面向对象的语言,如 C++,对模块化的支持是直接的,模块化是面向对象编程的核心
模块的质量 · 模块是否有一个中心目的? · 模块是否是围绕着一组公用数据进行组织的? · 模块是否提供了一套相互联系的功能? · 模块功能是否足够完备,从而使得其它模块不必干预其内部数据? · 一个模块相对其它模块是否是独立的?它们之间是松散耦合的吗? · 一个模块的实现细节,对其它模块来说,是隐含的吗? · 模块的接口是否抽象到了不必关心其功能实现方式的地步?它是作为一个黑盒子来设
计的吗? · 是否考虑过把模块再划分为单元模块?是否对其进行了充分的再划分工作? · 如果用不完全支持模块的语言编程,你是否制定了编程约定以使这种语言支持模块?
创建模块的原因有许多是与创建子程序相同的。但模块概念的意义要比子程序深远得 多,因为它可以提供一整套而不是单独一个功能,因此,它是比子程序更高层次的设 计工具。