第6章设计阶段 设计是运用专业知识针对确定的目标,提出具体解决方法的阶段。在设计阶 段,需要在各种解决办法中进行权衡,以确定最为合理的方案。因此,设计是一 个决策过程。在许多工程领域,如机械设计、电子设计、建筑设计行业,有着许 多设计规范、设计指南和计算公式,然而,在软件设计领域,目前似乎依然主要 依靠个人的经验和技艺进行决策,这就使得不同的人完成的软件设计有很大差别, 从而造成软件设计结果很难重用,软件的质量也很难保证。我们希望软件设计也 能够有系统化的、科学的方法,目的是遵照这一套方法,不同的人可以设计出差 别不大的系统,只有这样,设计的质量才能得到保证。 面向对象提供了一套从分析、设计、实现到测试的方法学。通过面向对象分 析已经建立了功能模型,对象模型和动态模型,在设计阶段,我们依然运用面向 对象方法,对类的定义进行细化,并将类组织成组件、子系统。由于分析阶段和 设计阶段都采用了对象模型,设计阶段的对象模型受到了分析阶段的对象模型的 直接启发,因此开展起来相对自然。然而,在设计阶段依然有许多决策是必须在 这个阶段做出的,例如整个系统需要分解成哪些子系统、整个软件的控制结构是 怎样的。本章中将围绕设计中的内容、方法、涉及到的模型和文档模板展开介绍。 值得指出的是,以面向对象的方式设计软件,与现实中创办一个企业、管理 一个企业有类似之处。作为软件设计者,要安排每一个软件对象的职责,确定它 们的交互方式,使得软件世界井然有序,运转高效;而作为企业的管理者,要安 排每一个人员的工作,确定他们之间的合作方式,使整个企业内责任明晰。保持 一个机构(无论是软件对象组成的机构,还是人组成的机构)高效运转的诀窍有 许多相似的原则,比如说,在一个企业中要使每一个人的职责比较明晰,不能把 过杂的责任分给一个人,在软件对象上,也是如此。因此,用管理好一个企业的 思维去考虑软件设计,是一个值得借鉴的思路。 6.1设计阶段的主要内容 设计阶段需要在不同层次上进行决策。我们把这种决策分为两个层次:系统 设计层和对象设计层
第 6 章 设计阶段 设计是运用专业知识针对确定的目标,提出具体解决方法的阶段。在设计阶 段,需要在各种解决办法中进行权衡,以确定最为合理的方案。因此,设计是一 个决策过程。在许多工程领域,如机械设计、电子设计、建筑设计行业,有着许 多设计规范、设计指南和计算公式,然而,在软件设计领域,目前似乎依然主要 依靠个人的经验和技艺进行决策,这就使得不同的人完成的软件设计有很大差别, 从而造成软件设计结果很难重用,软件的质量也很难保证。我们希望软件设计也 能够有系统化的、科学的方法,目的是遵照这一套方法,不同的人可以设计出差 别不大的系统,只有这样,设计的质量才能得到保证。 面向对象提供了一套从分析、设计、实现到测试的方法学。通过面向对象分 析已经建立了功能模型,对象模型和动态模型,在设计阶段,我们依然运用面向 对象方法,对类的定义进行细化,并将类组织成组件、子系统。由于分析阶段和 设计阶段都采用了对象模型,设计阶段的对象模型受到了分析阶段的对象模型的 直接启发,因此开展起来相对自然。然而,在设计阶段依然有许多决策是必须在 这个阶段做出的,例如整个系统需要分解成哪些子系统、整个软件的控制结构是 怎样的。本章中将围绕设计中的内容、方法、涉及到的模型和文档模板展开介绍。 值得指出的是,以面向对象的方式设计软件,与现实中创办一个企业、管理 一个企业有类似之处。作为软件设计者,要安排每一个软件对象的职责,确定它 们的交互方式,使得软件世界井然有序,运转高效;而作为企业的管理者,要安 排每一个人员的工作,确定他们之间的合作方式,使整个企业内责任明晰。保持 一个机构(无论是软件对象组成的机构,还是人组成的机构)高效运转的诀窍有 许多相似的原则,比如说,在一个企业中要使每一个人的职责比较明晰,不能把 过杂的责任分给一个人,在软件对象上,也是如此。因此,用管理好一个企业的 思维去考虑软件设计,是一个值得借鉴的思路。 6.1 设计阶段的主要内容 设计阶段需要在不同层次上进行决策。我们把这种决策分为两个层次:系统 设计层和对象设计层
1.系统设计 系统设计是有关系统总体构成的决定。对于一个具有一定复杂度的系统,我 们一般而言需要把它分解为子系统,以此来增加各个子系统的可重用性,降低开 发难度,也使得各个团队可以并行开发。 随着技术的发展,出现了具有不同结构特征的系统框架范型,包括Wb系统、 客户/服务器系统、对等系统等。我们可以按照这些系统架构去进行系统设计, 划分子系统的构成,确定各个子系统的接口。同时,目前也出现了许多中间件、 软件框架,开发系统时可以利用这些中间件、软件框架从而降低开发难度,提高 开发效率。使用成熟的中间件、软件框架进行开发也有助于提高系统的质量。 在系统设计时,要考虑系统的各种设计目标、与其他系统的集成、将来的维 护需求、技术风险等因素。这些设计目标有时候可能会相互冲突,我们需要在设 计中对这些设计目标进行权衡,做出合理的决策。 2.对象设计 在系统设计的基础上,我们需要进一步确定涉及到的软件对象,每个软件类 (此处也称为设计类)的属性、方法的详细定义,软件对象之间的具体交互形式。 我们从分析阶段的对象模型中获得启发,从中把软件中要实现的对应类抽取出来, 再参考分析阶段的动态模型,构造设计阶段的动态模型,并添加必要的类。由于 软件自有其独特之处,考虑到软件的可理解性、性能、未来的可重用性、重用已 有类或者子系统等因素,得到细化后的对象模型、动态模型,给软件实现以直接 的指导。在设计时,要灵活运用设计原则,一方面要考虑未来可能的变化,强调 架构的灵活性,另一方面,也要避免过于复杂的设计。 3.运行设计 随着软件系统的功能越来越复杂,性能要求越来越高,现代软件涉及到多进 程、多线程的越来越多。运行设计就是设计进程、线程和它们的运行关系,并把 设计元素分配到进程、线程中去。 4.实现设计 软件需要通过开发工具,编写代码,并经过编译形成可执行文件。我们需要 定义开发过程中采用的工具,需要编写的文件以及它们的依赖关系。同时,也需 要定义编译以后生成的组件以及它们的依赖关系
1. 系统设计 系统设计是有关系统总体构成的决定。对于一个具有一定复杂度的系统,我 们一般而言需要把它分解为子系统,以此来增加各个子系统的可重用性,降低开 发难度,也使得各个团队可以并行开发。 随着技术的发展,出现了具有不同结构特征的系统框架范型,包括 Web 系统、 客户/服务器系统、对等系统等。我们可以按照这些系统架构去进行系统设计, 划分子系统的构成,确定各个子系统的接口。同时,目前也出现了许多中间件、 软件框架,开发系统时可以利用这些中间件、软件框架从而降低开发难度,提高 开发效率。使用成熟的中间件、软件框架进行开发也有助于提高系统的质量。 在系统设计时,要考虑系统的各种设计目标、与其他系统的集成、将来的维 护需求、技术风险等因素。这些设计目标有时候可能会相互冲突,我们需要在设 计中对这些设计目标进行权衡,做出合理的决策。 2. 对象设计 在系统设计的基础上,我们需要进一步确定涉及到的软件对象,每个软件类 (此处也称为设计类)的属性、方法的详细定义,软件对象之间的具体交互形式。 我们从分析阶段的对象模型中获得启发,从中把软件中要实现的对应类抽取出来, 再参考分析阶段的动态模型,构造设计阶段的动态模型,并添加必要的类。由于 软件自有其独特之处,考虑到软件的可理解性、性能、未来的可重用性、重用已 有类或者子系统等因素,得到细化后的对象模型、动态模型,给软件实现以直接 的指导。在设计时,要灵活运用设计原则,一方面要考虑未来可能的变化,强调 架构的灵活性,另一方面,也要避免过于复杂的设计。 3. 运行设计 随着软件系统的功能越来越复杂,性能要求越来越高,现代软件涉及到多进 程、多线程的越来越多。运行设计就是设计进程、线程和它们的运行关系,并把 设计元素分配到进程、线程中去。 4. 实现设计 软件需要通过开发工具,编写代码,并经过编译形成可执行文件。我们需要 定义开发过程中采用的工具,需要编写的文件以及它们的依赖关系。同时,也需 要定义编译以后生成的组件以及它们的依赖关系
5.软硬件部署设计 软件最终需要部署到硬件上才能得到运行。因此,硬件平台配置(包括计算 机的配置、网络的配置、各种专门硬件如存储系统、各种外设如打印机等),软 件各个部分以什么样的形式分布在硬件系统上也是需要在设计阶段确定的。 6.数据管理设计 软件系统中都会涉及到数据的管理问题。尽管面向对象系统中已经把数据和 操作封装在一起,我们依然需要考虑数据持久化的问题。数据持久化是指数据的 保存。究竞采用何种数据保存的方式,以及具体的数据保存格式会对数据的访问 效率产生根本性的影响。 7.其他设计问题 软件设计中还要针对设计目标进行针对性的考虑。例如针对安全性,就有许 多方面需要考虑,包括访问控制、数据安全、防攻击等,针对可靠性,包括防错、 容错等。 我们将在本章中对这些设计步骤进行逐一介绍。需要指出的是软件设计是一 个迭代的过程,也就是说,它并非是沿着系统设计、对象设计、运行设计、实现 设计、软硬件部署设计、数据管理设计、其它设计这样一个线性过程,而是这些 步骤的交错迭代过程。 设计阶段的主要交付物包括: 1) 软件设计模型 2) 软件架构文档 6.2.软件设计的原则 无论是机械设计、建筑设计和电子设计中,都有一套设计原则,这些设计原 则应该贯彻在所有的设计实践中。软件设计也不例外。然而,相对而言,在机械 行业、建筑行业、电子行业都有比较成熟而详细的设计指南,软件行业仅仅有一 些设计原则,而且这些设计原则还比较抽象。 在本节中,我们介绍的设计原则,不仅适用于子系统层次,也适合于对象层 次。有些原则在分析阶段中就己经得到应用,这是为了与在软件中应用此原则一 致起来
5. 软硬件部署设计 软件最终需要部署到硬件上才能得到运行。因此,硬件平台配置(包括计算 机的配置、网络的配置、各种专门硬件如存储系统、各种外设如打印机等),软 件各个部分以什么样的形式分布在硬件系统上也是需要在设计阶段确定的。 6. 数据管理设计 软件系统中都会涉及到数据的管理问题。尽管面向对象系统中已经把数据和 操作封装在一起,我们依然需要考虑数据持久化的问题。数据持久化是指数据的 保存。究竟采用何种数据保存的方式,以及具体的数据保存格式会对数据的访问 效率产生根本性的影响。 7. 其他设计问题 软件设计中还要针对设计目标进行针对性的考虑。例如针对安全性,就有许 多方面需要考虑,包括访问控制、数据安全、防攻击等,针对可靠性,包括防错、 容错等。 我们将在本章中对这些设计步骤进行逐一介绍。需要指出的是软件设计是一 个迭代的过程,也就是说,它并非是沿着系统设计、对象设计、运行设计、实现 设计、软硬件部署设计、数据管理设计、其它设计这样一个线性过程,而是这些 步骤的交错迭代过程。 设计阶段的主要交付物包括: 1) 软件设计模型 2) 软件架构文档 6.2. 软件设计的原则 无论是机械设计、建筑设计和电子设计中,都有一套设计原则,这些设计原 则应该贯彻在所有的设计实践中。软件设计也不例外。然而,相对而言,在机械 行业、建筑行业、电子行业都有比较成熟而详细的设计指南,软件行业仅仅有一 些设计原则,而且这些设计原则还比较抽象。 在本节中,我们介绍的设计原则,不仅适用于子系统层次,也适合于对象层 次。有些原则在分析阶段中就已经得到应用,这是为了与在软件中应用此原则一 致起来
1.高内聚、低耦合原则 这是软件设计中最基本的原则。通过将功能相关的责任分配给一个类,实现 了类的高内聚,通过将功能相关的类组织成子系统,实现了子系统的高内聚。而 在类与类之间、子系统与子系统之间,使它们之间的交互尽量少,实现了低耦合。 高内聚、低耦合的原则是软件设计中的根本原则,其他原则都是依据此原则派生 而来。我们在分析阶段已经对此原则进行了介绍,在此就不再进一步展开。 2.“模型-视图”相分离原则 模型视图分离原则是高内聚、低耦合原则的一个应用。“模型”代表的是依据 领域类确定的设计类,它是从业务逻辑中抽取而来的,相对稳定。“视图”对应的 是人机接口。显然,不同用户对人机接口有不同的要求,修改意见也比较集中于 人机接口部分。通过模型视图的分离,使得人机接口的修改不影响模型对应的设 计类,从而提高了系统的可维护性。 3.关注点分离原则 关注点分离原则强调软件元素应该具有互不相关的目的。也就是说,一个元 素承担的职责比较专一,它不会去承担应该由另一个元素承担的职责。关注点的 分离是通过明确边界来达成的。边界是任何逻辑或者物理的限制,它能给一组特 定的职责划定界限。关注点分离的目标是使各个软件元素各司其职,从而形成一 个具有良好秩序的系统。 将关注点分离原则应用于软件设计有许多的好处。首先,每一个软件元素的 目的单一会使得整个系统更易于维护,提高了可维护性后,系统整体也会变得更 加稳定;由软件元素专注于单一目标所形成的解耦,使得在它其它系统中的复用 变得容易。关注点分离也是现实世界中组织管理的一个理念,它使得团队责任明 确。 4.重用的原则 在成熟的工业中,部件(系统)可重用是大规模生产的前提。例如在机械行 业、电子行业中,各个零部件具有高度的可重用性、互换性。软件行业需要向成 熟工业学习,首先就是要学习可重用性。以往的可重用的软件部件,有的可以不 加修改直接使用,有的进行修改后就可以再用,从而大大提高了生产效率,同时, 可重用的软件元素经过了严格的质量保证,重用它们有助于提高整个软件产品的 质量。所以在软件设计过程中,始终要考虑重用性的问题:一方面,需要考虑可
1. 高内聚、低耦合原则 这是软件设计中最基本的原则。通过将功能相关的责任分配给一个类,实现 了类的高内聚,通过将功能相关的类组织成子系统,实现了子系统的高内聚。而 在类与类之间、子系统与子系统之间,使它们之间的交互尽量少,实现了低耦合。 高内聚、低耦合的原则是软件设计中的根本原则,其他原则都是依据此原则派生 而来。我们在分析阶段已经对此原则进行了介绍,在此就不再进一步展开。 2. “模型-视图”相分离原则 模型视图分离原则是高内聚、低耦合原则的一个应用。“模型”代表的是依据 领域类确定的设计类,它是从业务逻辑中抽取而来的,相对稳定。“视图”对应的 是人机接口。显然,不同用户对人机接口有不同的要求,修改意见也比较集中于 人机接口部分。通过模型视图的分离,使得人机接口的修改不影响模型对应的设 计类,从而提高了系统的可维护性。 3. 关注点分离原则 关注点分离原则强调软件元素应该具有互不相关的目的。也就是说,一个元 素承担的职责比较专一,它不会去承担应该由另一个元素承担的职责。关注点的 分离是通过明确边界来达成的。边界是任何逻辑或者物理的限制,它能给一组特 定的职责划定界限。关注点分离的目标是使各个软件元素各司其职,从而形成一 个具有良好秩序的系统。 将关注点分离原则应用于软件设计有许多的好处。首先,每一个软件元素的 目的单一会使得整个系统更易于维护,提高了可维护性后,系统整体也会变得更 加稳定;由软件元素专注于单一目标所形成的解耦,使得在它其它系统中的复用 变得容易。关注点分离也是现实世界中组织管理的一个理念,它使得团队责任明 确。 4. 重用的原则 在成熟的工业中,部件(系统)可重用是大规模生产的前提。例如在机械行 业、电子行业中,各个零部件具有高度的可重用性、互换性。软件行业需要向成 熟工业学习,首先就是要学习可重用性。以往的可重用的软件部件,有的可以不 加修改直接使用,有的进行修改后就可以再用,从而大大提高了生产效率,同时, 可重用的软件元素经过了严格的质量保证,重用它们有助于提高整个软件产品的 质量。所以在软件设计过程中,始终要考虑重用性的问题:一方面,需要考虑可
以重用哪些现成的元素,从而能够改进开发,另一方面,需要考虑正在开发的软 件如何提高可重用性,以利于后续的开发。 可重用的软件元素不仅包括程序(如子系统、组件、类库、代码等)、也可 以是测试用例、设计文档、设计过程、标准,甚至是设计知识。6.3节中我们将 对此进行更为详细的阐述。 6.3从可重用软件单元到可重用设计知识 典型的可重用的软件元素包括类库、框架、中间件,而典型的可重用的软件 设计知识就是设计模式。 6.3.1类库 类库(Class Library)是类的集合,一般的类库用以解决一系列常见编程任 务(包括诸如字符串管理、数据收集、数据库连接以及文件访问等任务),也有 针对不同开发任务的类库(如语音处理,图像处理,算法等)。围绕各种程序设 计语言,都有大量的类库,从而形成了一个开发语言的生态环境。可以说类库的 丰富程度是决定一个语言是否得到广泛应用的重要要素。 6.3.2软件框架 虽然通过类的重用可以提高开发效率,但是这种重用在实践中存在着一些不 足:(1)目前的类库日趋其庞大以致于使用人员难以掌握:(2)大多数类的粒 度还太小,人们不得不将多个类的对象组合起来并作为一个整体来使用。这就使 得人们逐渐追求更大规模的软件重用。 软件框架(Software Framework),可以指的是为了实现某个业界标准或完 成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范 所要求的基础功能的软件产品,我们此处用的是第二个含义。 软件框架是面向某领域的、可复用的“半成品”软件,它实现了该领域的共 性部分,并提供一系列定义良好的“可变点”以保证灵活性和可扩展性。 所谓软件框架中的“可变点”有以下四种情况: (1)模板参数化:软件框架提供代码自动生成工具,该工具根据用户设置的参
以重用哪些现成的元素,从而能够改进开发,另一方面,需要考虑正在开发的软 件如何提高可重用性,以利于后续的开发。 可重用的软件元素不仅包括程序(如子系统、组件、类库、代码等)、也可 以是测试用例、设计文档、设计过程、标准,甚至是设计知识。6.3 节中我们将 对此进行更为详细的阐述。 6.3 从可重用软件单元到可重用设计知识 典型的可重用的软件元素包括类库、框架、中间件,而典型的可重用的软件 设计知识就是设计模式。 6.3.1 类库 类库(Class Library)是类的集合,一般的类库用以解决一系列常见编程任 务(包括诸如字符串管理、数据收集、数据库连接以及文件访问等任务),也有 针对不同开发任务的类库(如语音处理,图像处理,算法等)。围绕各种程序设 计语言,都有大量的类库,从而形成了一个开发语言的生态环境。可以说类库的 丰富程度是决定一个语言是否得到广泛应用的重要要素。 6.3.2 软件框架 虽然通过类的重用可以提高开发效率,但是这种重用在实践中存在着一些不 足:(1)目前的类库日趋其庞大以致于使用人员难以掌握;(2)大多数类的粒 度还太小,人们不得不将多个类的对象组合起来并作为一个整体来使用。这就使 得人们逐渐追求更大规模的软件重用。 软件框架(Software Framework),可以指的是为了实现某个业界标准或完 成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范 所要求的基础功能的软件产品,我们此处用的是第二个含义。 软件框架是面向某领域的、可复用的“半成品”软件,它实现了该领域的共 性部分,并提供一系列定义良好的“可变点”以保证灵活性和可扩展性。 所谓软件框架中的“可变点”有以下四种情况: (1)模板参数化:软件框架提供代码自动生成工具,该工具根据用户设置的参