一.模块化与信息隐藏思想
1.设计质量
- 好的设计要着重满足以下3方面:可管理性、灵活性、可理解性
- 好的设计需要侧重于间接性和可观察性——简洁性使得系统模块易于管理(理解和分解)、开发(修改与调试)和复用。
- 实践者都同意可理解、易修改和易复用是软件设计中比较常见和重要的质量标准~
软件的变更是不可避免的,复用则是人们在实践中提高软件生产效率最好的方式之一,因此我们在设计过程中不得不考虑以上提到的软件质量特性,以使我们的软件成为好的软件~
2.动机
模块化和信息隐藏就是为了实现上述重要的质量标准而提出的设计方法,因为他们所针对的是最为重要的软件设计标准,被视为软件设计的核心思想之一。
在分解独立模块的过程中,方法是衡量模块的内聚性和耦合性,希望分解建立高内聚、低耦合的模块~
3.发展
总的来说,模块化和信息隐藏的思想是顺着下面的路线前进的:
- 从意识到要分解模块开始
- 之后人们慢慢意识到要分解出高内聚和低耦合的模块,使得结构化方法慢慢盛行起来,后来意识到从数据的角度来分解实现数据的封装
- 抽象数据类型提出之后,人们越来越意识到信息隐藏思路的重要性
- 再加上继承、多态等思想,完善了类和对象的概念,逐步走向了面向对象方法的世界
二.模块化
1.分解与模块化
分解:将系统分为多个小模块,降低复杂度
模块:一个词汇上邻接的程序语言序列,由边界元素限制范围,有一个聚合标识符(通俗的说就是一个可通过名称调用的代码片段)
在结构化方法中,代码片段式程序设计语言中的函数、过程和模块;而在面向对象方法中,代码片段则是面向对象程序设计语言中的类、方法和模块——无论具体存在如何,模块化的原则是通用的——尤其是最重要的高内聚低耦合原则:模块内部又最大的关联,模块之间有最小的关联~
2.结构化设计中的耦合
模块之间的联系越多,联系的复杂程度越高,模块之间的关系就约为复杂。
耦合:描述两个模块关系之间的复杂程度——模块耦合性越高,模块的划分越差,越不利于软件的变更和复用~
- 内聚耦合:最高级别的耦合,耦合性最强
- 公共耦合:较弱于前者,但耦合性仍然很强
- 重复耦合:非常隐蔽的耦合,往往不容易发现却危害甚大——同样的逻辑代码如果存在,在变更时就要同时修改多处
- 控制耦合:一个模块明确控制着另一个模块的逻辑——难点是两个模块都是非独立的,他们都需要知道另一个的内部结构和逻辑
- 印记耦合:如果把数据结构作为参数进行传输,被调用的模块只在该数据结构的个别组件上进行操作~(关键点在于共享的是数据结构)
- 数据耦合:模块之间通过参数传递,只共享对方需要的数据
(前3种是必须消除的,数据耦合是最理想的,另外两个是可以接受的)
3.结构化设计中的内聚
内聚:表达的是一个模块内部的联系的紧密性。
内聚性越高越好,越低越不容易实现变更和复用
- 偶然内聚:是指模块中执行的操作毫无关系,只是恰好堆砌在这个模块内。比如修车、烤蛋糕、遛狗、看电影放在一个模块内,没有任何联系。
- 逻辑内聚:指的是模块执行一系列逻辑上相似但没有直接关联的操作。比如乘坐汽车、乘坐火车、乘坐轮船和乘坐飞机,它们都是交通方式这个系列的操作。
- 时间类聚:也是模块中执行一系列操作,但是这些操作在同一时间段内发生。比如,我们睡觉前要把奶瓶放到门外、让猫出去溜达、关闭电视机和刷牙。这些都是在同一个时间段内完成,它们之间有时间相关性。
- 过程内聚:是模块执行的多个操作,是解决同一个问题的不同步骤。比如保养车的过程依次为洗车、消除凹痕、打磨和上蜡。这些子过程之间是有顺序关系的。
- 通信内聚则是模块内的操作都是针对同一数据进行的。比如查询书名、查询价格、查询出版社和查询作者。
- 功能内聚:只执行一个单一目的的操作。比如计算平方根、计算最短路径或者压缩数据库。
- 信息内聚:是模块内有一系列操作,每个操作都有各自的入口点和出口点,每个操作的代码相对独立,而且所有操作都是在相同的数据结构上完成,但是却形成一个抽象的整体。信息内聚的模块主要用来实现抽象的数据类型。
在上述各种内聚类型中,功能内聚和信息内聚是最好的两种,而且这两者的出发点不同,一个完全以功能(行为)为依据进行模块分解,一个以数据与功能间的相互支撑为依据进行模块分解,不可相互比较。一般而言,函数与过程应该是功能内的(信息内不适用于函数与过程),模块应该是信息内聚或功能内聚的,面向对象方法中的类应该是信息内聚与功能内聚兼顾的。
偶然内聚与逻辑内聚是不能接受的,如果软件中出现这两类内聚,一定要进行优化。
通信内聚、过程内聚、时间内聚这3种类型的内聚也是各自具有不同的出发点(一个是相同的数据;一个是相同的问题;一个是相同的时间),无法相互比较。这3种类型的内聚都是可以接受而且不可避免的。
三.信息隐藏
1.抽象信息与隐藏
- 抽象的本质就是总结提炼本质特征,消除非本质的细节,从而使得人们可以聚焦在本质上,降低认知的复杂性~
- 信息隐藏:本质上是利用了抽象的方法,抽象出每个类的关键细节,也就是模块的职责——什么是公开给其他人的,什么事隐藏在自己模块中的
- 换句话说,抽象出来的就是接口,隐藏的就是实现,他们共同体现了模块的职责——体现了抽象可以让面向对象方法拥有更好的效率和更多的灵活性~
- 核心设计思路:每个模块都隐藏一个重要的设计决策——对外表现为一份契约,并在这份契约之下隐藏着只有这个模块知道的设计决策或者秘密,决策实现的细节只有模块自己知道
2.信息与隐藏
模块的秘密:
- 根据需求分配的职责
- 内部实现机制
职责就是用一定的方式把模块的信息、秘密等隐藏起来~(隐藏独立变化的系统细节,分隔不一致变化的模块,只暴露出不容易变化的接口)
3.模块说明
即,用文档化的方式总结模块的设计决策,内容如下:
- 主要秘密:实现的用户需求
- 次要秘密:所设计的关键实现细节
- 角色:角色、作用、关系
- 对外接口:提供给别的模块