第七章 高级结构设计
7.2 结构化设计
结构化设计这一概念是1974年在《IBM 系统日报》(IBM System Journal)一篇论文中出现 的。在后来由 Ed Yourdon 和 Larry Constantine 写进《Structured Design:Fundamentals of a Discipline of Computer Program and Systems Design》书中(1971),对其作了全面补充与扩展。 Constantine 是最初那篇论文的作者之一,而“自顶向下设计”一词则是指一种非正式的结构化设计,类似 的词还有“逐步求精”和“分解”等,指的基本都是同一意思。结构化设计是与其它结构化设 计方法一道使用的。
结构化设计是由以下部分组成的:
・ 系统组织,系统将被设计成几个黑盒子,明确定义的子程序和模块、接口的实现细节对 其它子程序来说都是隐含的。
・ 开发设计的策略。
・ 评估设计准则。
・ 关于问题的明确说明,这是解决问题的指导原则。
・ 表达设计的图形和语言工具,包括 PDL 和结构图。
在下面的内容中,将对这些内容作比较详细的论述。
7.2.1 选择需进行模块化的要素
在前面几章论述了程序和模块相关好坏的标准,并提供了确定子程序和模块质量的检查表,
但并没有给出识别子程序和模块的方法,在本节中,将论述这一问题的指导原则。
自顶向下分解
把程序分解为子程序的一种流行方法是自顶向下分解,也称为自顶向下设计或逐步求精。
其特点是从关于程序功能的粗略说明出发,逐步推进到程序要做的每一项特定的工作。从粗略 的层次出发往往是指从程序中的“主要”子程序出发,通常,把这个子程序画在结构图的顶部。
以下是几项在进行自顶向下分解时要牢记的原则:
・ 设计高层次。
・ 避免特定语言细节。从设计中,不应该看出打算在程序中使用什么语言,或者说当在设 计中更换要用的语言时,不会产生任何麻烦。
・ 暂时不指出下一层次的设计细节(与信息隐含类似)。
・ 正规化每个层次。
・ 检验每个层次。
・ 转移到下一个层次,进行新的求精工作。
自顶向下设计指导原则的依据是:人脑一次只能考虑有限数量的细节。如果你从一个较简 略的子程序开始,逐步把它分解成更加详细的子程序,就不必每次考虑过多的细节。这种方法 也常称之为“分而治之”战术。它对于分层结构往往是最有效的。如图 7-2 所示。
从两个方面来看,这种分而治之战术是一个逐次迭代逼近的过程,首先,这是由于往往在 一次分解之后你并不会马上停止,还要进行下几个层次的分解。其次,是由于分解并不是一蹴 而就的,采用某种方法分解一个程序,再看一下效果,然后,又用另外一种方法来分解这个程 序,看效果是否会好些,在几次尝试之后,就有了一个很好的办法,同时也知道为什么这样做。
需要把一个程序分解到什么程度呢?要持续不断地分解,直到看起来下一步进行编码要比 再分解要容易为止,或者到你认为设计已经非常明了详细,对再分解已经感到不耐烦为止,到 这时,可以认为分解已经完成了。由于你比任何人都熟悉这个问题,而且也比任何人都清楚,
因此,你要确保其解决方案是很容易理解的,如果连你都对解决方案有些困惑的话,那么,试 想一下,又有谁会理解它呢?
自底向上合成
有时候,自顶向下方法过于抽象以至于让人不知从何下手。如果想要进行一些具体的工作,
那么可以试一下自底向上的设计方法,如图 7-2 所示。你可以问自己,“这个系统需要做什么?”
毫无疑问,你能够回答这个问题。你可以识别出系统需要具备的较低层次的功能,例如,你可 能知道这个系统需要进行报告格式化、计算报告总数、用不同颜色在屏幕上显示字母等等。当 你识别出某些低层次功能后,再从事较高层设计可能会有把握些。
以下是一些在进行自底向上合成时要牢记的原则:
・ 问自己,关于系统要做什么你都知道哪些?
・ 利用这一问题识别出某些低层次功能。
・ 识别出这些低层次功能共同的方面,将其组合到一起。
・ 向上一个层次,进行同样的工作,或回到顶端开始自顶向下。
其中自顶向下是从一般到特珠,自底向上是从特殊到一般。
自顶向下与自底向上
自底向上与自顶向下策略的首要区别是前者是合成,而后者则是分解。一个是从可控制的 零散问题出发,把它们合成到一起从而获得一个总体解决方案,而另一个则从总体问题出发,
将其分解成可控制的零散问题。两种方法各有优缺点。在实际使用时要详加比较。
自顶向下设计方法的特点是比较简单,人们往往擅长把大问题分解成小问题,而程序员们 则更是擅长这点。当一个问题是用层次结构模型化的时候,自上而下的分解方法恰好与其相符。
自顶向下设计的另一个优点是你可以避开实现细节。由于系统常常受到实现细节变动的干 扰(比如文件结构或报告格式的变化),因此把这些细节隐含在层级结构的底部,而不是让它在 顶部起支配作用,是非常有益的。
这种设计方法也有它的缺点。其中之一是系统的总体功能可能是很难识别的。关于系统所 作的最重要决定之一就是如何进行第一步分解工作,而在自上向下设计中,刚开始接触系统,
对其了解还很少时,便不得不做出这一决定,这是很危险的。它的另一个缺点是:由于许多系 统本身并不是层级结构的,因此是很难清晰地分解。或许这种设计方法的最大缺点就是它要求 系统在顶层要有一个单一而又清楚的功能,而对于现代事件驱动系统来说,这是很难想象的。
自底向上设计方法的优点是它在早期就可以识别出有用的功能子程序,结果是坚实可靠的 设计。如果已经开发了相似的系统,那么可以参阅一下旧系统,看看有什么可以借用的。
这种方法的弱点是很难单独地使用它。因为大多数人都不善于从小的概念出发形成综合 的设想。这就像一个自己组装的玩具,我想我已经组装完了,怎么盒子中还有零件呢?好在,
你不必单独使用它。
它的另一个弱点是,有时从你识别出的细节出发,无法建造出整个程序,就像你无法用砖头 造出一架飞机一样。而且当你知道在底部需要什么功能时,你可能已经不得不进行顶层设计了。
不过,这两种方法并不是互相矛盾的。设计是一个启发的过程,就是说没有一种百试不爽 的设计方法,它总是一个尝试的过程。因此,在找到好方法之前,尽可以大胆尝试,可以用自 顶向下工作一会儿,再用自底向上工作一会儿。
设计也是一个逐次迭代逼近的过程。因此,你在第 n 次用自底向上方法学到的东西,将在 第 n+l 次用自顶向下方法设计时起到很大帮助作用。