另一个部分(客户子系统)。请求服务的对象都归于客户子系统,而接受请求提供服务的部分 就是服务器。X- window系统在用户界面设计时就使用了客户一服务器方法来构造它的图形 交互界面。一个应用的核心“引擎”是服务器子系统的客户,如用户界面、打印服务器、数 据库服务器等 窗口 其它系统 人机交互 问题论域 系统交互 界面 畀面 报告 数据管理 设备 文件 RDBMS 图6.11OOD设计导出的体系结构 在 Smalltalk中使用的软件体系结构是模型/视图/控制器(MVC, Model/view/ Controller),参看图612。在这个结构中,模型是软件中的应用 论域的各种对象,它们的操作独立于用户界面:视图则管理用 户界面的输出:而控制器处理软件的输入。输入事件给出要发 视图 送给模型的消息。一旦模型改变了它的状态,就立即通过关联(模型 机制通知视图,让视图刷新显示。这个关联机制定义了在模型 与各个视图之间的关系,它允许模型的运行独立于与它相关联 控制器 的视图。类似地,控制器在输入事件发生时将对视图及模型进 行控制与调度。 图6.12MVC框架结构 此外,在软件体系结构中还使用了许多其它配置。类的配置表示的多是子系统的体系结 构而不是系统的总体结构。它们是一些抽象类的集合,可以定义这些抽象类的新的派生类, 并把它们实例化,以实现所要求的特定行为,籍此构造要求的应用软件。对于MVC来说, 可以通过开发模型的一个派生类,履行与应用相关联的处理,建立这个应用软件。用户界面 通过定义视图和控制器的派生类来建立,这些派生类中许多是可复用的既存类,像按钮和对 话框等在多数 Smalltalk系统中已经存在。这样就导致了新子系统的建立。 ②高层设计的规则 最小化各构件间的通信:在子系统的各个高层构件之间的通信量应当达到最小。一个 用户界面应当能够自行处理交互、错误改正和硬件控制,而不需打扰主应用。 隐藏复杂性:子系统应当把那些成组的类打包,形成高度的内聚 逻辑功能分组:虽然输入和输出设备可能相互间不通信,但逻辑上把它们归组到一个 处理输入/输出的子系统中。这样比较容易识别并定位问题论域中的事件。 类与通过概念封装的子系统十分类似。事实上,每个子系统都可以被当做一个类来实现, 这个类聚集它的构件,提供了一组操作。类和子系统的结构是正交的,一个单个类的实例可 能是不止一个子系统的一部分 高层设计阶段增加了一批必要的类,主要包括了那些可使应用软件与系统的外部世界交 互的类。这些交互则包括与其它软件系统(如数据库管理系统、鼠标和键盘)的界面,与使用 来进行数据收集或者负责控制的硬件设备的界面等
11 另一个部分(客户子系统)。请求服务的对象都归于客户子系统,而接受请求提供服务的部分 就是服务器。X-window 系统在用户界面设计时就使用了客户—服务器方法来构造它的图形 交互界面。一个应用的核心“引擎”是服务器子系统的客户,如用户界面、打印服务器、数 据库服务器等。 图 6.11 OOD 设计导出的体系结构 在 Smalltalk 中使用的软件体系结构是模型/视图/控制器(MVC,Model/View/ Controller),参看图 6.12。在这个结构中,模型是软件中的应用 论域的各种对象,它们的操作独立于用户界面;视图则管理用 户界面的输出;而控制器处理软件的输入。输入事件给出要发 送给模型的消息。一旦模型改变了它的状态,就立即通过关联 机制通知视图,让视图刷新显示。这个关联机制定义了在模型 与各个视图之间的关系,它允许模型的运行独立于与它相关联 的视图。类似地,控制器在输入事件发生时将对视图及模型进 行控制与调度。 此外,在软件体系结构中还使用了许多其它配置。类的配置表示的多是子系统的体系结 构而不是系统的总体结构。它们是一些抽象类的集合,可以定义这些抽象类的新的派生类, 并把它们实例化,以实现所要求的特定行为,籍此构造要求的应用软件。对于 MVC 来说, 可以通过开发模型的一个派生类,履行与应用相关联的处理,建立这个应用软件。用户界面 通过定义视图和控制器的派生类来建立,这些派生类中许多是可复用的既存类,像按钮和对 话框等在多数 Smalltalk 系统中已经存在。这样就导致了新子系统的建立。 ② 高层设计的规则 ▪ 最小化各构件间的通信:在子系统的各个高层构件之间的通信量应当达到最小。一个 用户界面应当能够自行处理交互、错误改正和硬件控制,而不需打扰主应用。 ▪ 隐藏复杂性:子系统应当把那些成组的类打包,形成高度的内聚。 ▪ 逻辑功能分组:虽然输入和输出设备可能相互间不通信,但逻辑上把它们归组到一个 处理输入/输出的子系统中。这样比较容易识别并定位问题论域中的事件。 类与通过概念封装的子系统十分类似。事实上,每个子系统都可以被当做一个类来实现, 这个类聚集它的构件,提供了一组操作。类和子系统的结构是正交的,一个单个类的实例可 能是不止一个子系统的一部分。 高层设计阶段增加了一批必要的类,主要包括了那些可使应用软件与系统的外部世界交 互的类。这些交互则包括与其它软件系统(如数据库管理系统、鼠标和键盘)的界面,与使用 来进行数据收集或者负责控制的硬件设备的界面等。 图 6.12 MVC 框架结构
高层设计可以表征为标识和定义模块的过程。但这种模块可以是单个的类,还可以是由 些类组合成的子系统。定义过程是职责驱动的 高层设计和类设计这两个阶段是相对封闭的。在这种情况下,应用软件中的每一个事物 都是一个对象,包括应用软件自身在内!根据这个思想,这两个阶段又是连接的。应用软件 的设计是大类的设计,这种类设计考察应用软件所期望的每一个行为,并利用这些行为形成 应用类的界面 (2)类设计的目标和方针 类设计的第一步是标识应用所需的概念。应用分析过程包括了对问题论域所需的类的模 型化;但在最终实现应用时不只有这些类,还需要追加一些类。在类设计的过程中应当做这 些工作。类设计的主要目标如下: ①单一概念的模型:在分析与高层设计阶段,常常需要使用多个类来表示一个“概念”。 般人们在使用面向对象方法开发软件时,常常把一个概念进行分解,用一组类来表示这个 概念。当然,也可以只用一个独立的类来表示一个概念 ②可复用的“插接相容性”构件:我们希望所开发的构件可以在未来的应用中使用 因此,需要一些附加特性。例如,在相关的类的集合中界面的标准化,在一个集合内部的类 的“插接相容性”等 ③可靠的构件:应用软件必须是可靠的(健壮的和正确定义的)软件。而这种可靠性与 它的构件有关。每个构件必须经过充分的测试。但由于成本关系,往往测试不够完备。然而 如果我们要建立可复用的类,则通过测试确保构件的可靠性是绝对必要的。 ④可集成的构件:我们希望把类的实例用到其它类的开发和应用中,这要求类的界面 应当尽可能小,一个类所需要的数据和操作都定义在类定义中。因此,类的设计应当尽量减 少命名冲突。面向对象语言的消息语法可通过鉴别带有实例名的操作名来减少可能的命名冲 类结构提供的封装使得把概念集成到应用的工作变得很容易。封装特性保证了把一个概 念的所有细节都组合在一个界面下,而信息隐蔽则保证了实现级的名字将不会其它类的名字 互相干扰 我们讨论的方针是类的模块设计的方针,还要给出类设计质量的度量。 ①信息隐蔽:软件设计通过信息隐蔽可增强抽象,并可保护类的存储表示不被抽象数 据类型实例的用户直接存取。对其表示的唯一存取途径只能是界面。 ②消息限制:类的设计者应当为类的命令设计一个明确的界面,该类实例的用户应当 只使用界面提供的操作。 ③狭窄界面:不是所有的操作都是公共的。只有对其它类的实例是必要的操作才放到 界面上,其它操作应是隐蔽实现的部分。 ④强内聚:模块内部各个部分之间应有较强的关系,它们不能分别标识。 ⑤弱耦合:一个单独模块应尽量不依赖于其它模块。如果在类A的实例中建立了类B 的实例,或者如果类A的操作需要类B的实例做为参数,或者如果类A是类B的一个派生 类,则称类A“依赖于”类B。一个类应当尽可能少地依赖于其它类 耦合程度部分依赖于所使用的分解方法。类A之所以依赖于类B,是因为类A要求类B 提供服务。这个依赖性可通过复制类A中的类B的功能来消除。但代码的复制减少了系统的 灵活性并增加了维护的困难。继承结构损害了弱耦合的概念。因为在建立一般化-特殊化关系 的时候,继承引入了依赖 ⑥显式信息传递:除了依赖于最少的类外,还应该明确在这些类之间的信息流。在类 之间全局变量的共享隐含了信息的传递,并且是一种依赖形式。因此,两个类之间的交互应 当仅涉及显式信息传递。显式信息传递是通过参数表来完成的
12 高层设计可以表征为标识和定义模块的过程。但这种模块可以是单个的类,还可以是由 一些类组合成的子系统。定义过程是职责驱动的。 高层设计和类设计这两个阶段是相对封闭的。在这种情况下,应用软件中的每一个事物 都是一个对象,包括应用软件自身在内! 根据这个思想,这两个阶段又是连接的。应用软件 的设计是大类的设计,这种类设计考察应用软件所期望的每一个行为,并利用这些行为形成 应用类的界面。 (2) 类设计的目标和方针 类设计的第一步是标识应用所需的概念。应用分析过程包括了对问题论域所需的类的模 型化;但在最终实现应用时不只有这些类,还需要追加一些类。在类设计的过程中应当做这 些工作。类设计的主要目标如下: ① 单一概念的模型 :在分析与高层设计阶段, 常常需要使用多个类来表示一个“概念”。 一般人们在使用面向对象方法开发软件时,常常把一个概念进行分解,用一组类来表示这个 概念。当然,也可以只用一个独立的类来表示一个概念。 ② 可复用的“插接相容性”构件 :我们希望所开发的构件可以在未来的应用中使用。 因此,需要一些附加特性。例如,在相关的类的集合中界面的标准化,在一个集合内部的类 的“插接相容性”等。 ③ 可靠的构件 :应用软件必须是可靠的(健壮的和正确定义的)软件。而这种可靠性与 它的构件有关。每个构件必须经过充分的测试。但由于成本关系,往往测试不够完备。然而, 如果我们要建立可复用的类,则通过测试确保构件的可靠性是绝对必要的。 ④ 可集成的构件 :我们希望把类的实例用到其它类的开发和应用中,这要求类的界面 应当尽可能小,一个类所需要的数据和操作都定义在类定义中。因此,类的设计应当尽量减 少命名冲突。面向对象语言的消息语法可通过鉴别带有实例名的操作名来减少可能的命名冲 突。 类结构提供的封装使得把概念集成到应用的工作变得很容易。封装特性保证了把一个概 念的所有细节都组合在一个界面下,而信息隐蔽则保证了实现级的名字将不会其它类的名字 互相干扰。 我们讨论的方针是类的模块设计的方针,还要给出类设计质量的度量。 ① 信息隐蔽 :软件设计通过信息隐蔽可增强抽象,并可保护类的存储表示不被抽象数 据类型实例的用户直接存取。对其表示的唯一存取途径只能是界面。 ② 消息限制 :类的设计者应当为类的命令设计一个明确的界面,该类实例的用户应当 只使用界面提供的操作。 ③ 狭窄界面 :不是所有的操作都是公共的。只有对其它类的实例是必要的操作才放到 界面上,其它操作应是隐蔽实现的部分。 ④ 强内聚 :模块内部各个部分之间应有较强的关系,它们不能分别标识。 ⑤ 弱耦合 :一个单独模块应尽量不依赖于其它模块。如果在类 A 的实例中建立了类 B 的实例,或者如果类 A 的操作需要类 B 的实例做为参数,或者如果类 A 是类 B 的一个派生 类,则称类 A“依赖于”类 B。一个类应当尽可能少地依赖于其它类。 耦合程度部分依赖于所使用的分解方法。类 A 之所以依赖于类 B,是因为类 A 要求类 B 提供服务。这个依赖性可通过复制类 A 中的类 B 的功能来消除。但代码的复制减少了系统的 灵活性并增加了维护的困难。继承结构损害了弱耦合的概念。因为在建立一般化-特殊化关系 的时候,继承引入了依赖。 ⑥ 显式信息传递 :除了依赖于最少的类外,还应该明确在这些类之间的信息流。在类 之间全局变量的共享隐含了信息的传递,并且是一种依赖形式。因此,两个类之间的交互应 当仅涉及显式信息传递。显式信息传递是通过参数表来完成的
⑦派生类当做派生类型:继承结构的使用是面向对象开发方法的一大特色。每个派生 类应该当做基类的特殊化来开发,而基类所具有的公共界面成为派生类的共有界面的一个子 集。C++允许设计者选择类的基类是共有的或私有的。如果基类是共有的,则其共有界面将 成为新的派生类的共有界面部分,这表明基类的行为成为派生类的行为部分。这类似于类型 与派生类型之间的关系。如果基类是私有的,它的行为将不是继承类的公共行为部分而是实 现部分。它的提出是为了提供实现新类的服务。 ⑧抽象类:某些语言提供了一个类,用它做为继承结构的开始点,所有用户定义的类 都直接或间接以这个类为基类。 Smalltalk提供了一个类 Object做为所有类的继承树的根,而 C++则支持多重继承结构。每一种结构都包含了一组类,它们是(或应该是)某种概念的特殊 化。这个概念应抽象地由结构的根类来表示。因此,每个继承结构的根类应当是目标概念的 个抽象模型。这个抽象模型生成一个类,它不用于产生实例。它定义了一个最小的共有界 面,许多派生类可以加到这个界面上以给出概念的一个特定视图。 (3)通过复用设计类 利用既存类来设计类,有4种方式:选择,分解,配置和演变。这是面向对象技术的一 个重要优点。许多类的设计都是基于既存类的复用。 ①选择:设计类最简单的方法是从既存构件中简单地选择合乎需要的构件。这就是开 发软件库的目的。一个OO开发环境应提供常用构件库,大多数语言环境都带有一个原始构 件库(如整数、实数和字符),它是基础层。任一基本构件库(如“基本数据结构”构件)都应 建立在这些原始层上。这些都是些一般的和可复用的类。这个层还包括一组提供其它应用论 域服务的一般类,如窗口系统和图形图元。表6.1显示了建立在这些层上面的特定域的库。 最低层的论域库包括了应用论域的基础概念并支持广泛的应用开发。特定项目和特定组的库 包括一些论域库,它包含为相应层所定义的信息。 表6.1一个面向对象构件库的层次 特定组的构件 个小组为他们自己组内所有成员使用而开发 特定项目的构件 一个小组为某一个项目而开发 诗定问题论域的构件 购自某一个特定论域的软件销售商 般构件 购自专门提供构件的销售商 特定语言原操作一购自一个编译器的销售商 ②分解:最初标识的“类”常常是几个概念的组合。在设计时,可能会发现所标识的 操作落在分散的几个概念中,或者会发现,数据属性被分开放到模型中拆散概念形成的几个 组内。这样我们必须把一个类分成几个类,希望新标识的类容易实现,或者它们已经存在。 ③配置:在设计类时,可能会要求由既存类的实例提供类的某些特性。通过把相应类 的实例声明为新类的属性来配置新类。例如,一种仿真服务器可能要求使用一个计时器来跟 踪服务时间。设计者不必开发在这个行为中所需的数据和操作,而是应当找到计时器类,并 在服务器类的定义中声明它。 ④演变:要开发的新类可能与一个既存类非常类似,但不完 起重车 全相同。此时,不适宜采用“选择”操作,但可以从一个既存类演 类 变成一个新类,可以利用继承机制来表示一般化一特殊化的关系。特 殊化处理有三种可能的方式 汽车类 ·由既存类建立子类:现要建立一个新类“起重车”。它的 许多属性和服务都在既存类“汽车”中。关系如图6.13所示。新类 图6.13建立子类 是既存类的特殊情形。这时直接让“起重车”类作为“汽车”类的子类即可
13 图 6.13 建立子类 ⑦ 派生类当做派生类型 :继承结构的使用是面向对象开发方法的一大特色。每个派生 类应该当做基类的特殊化来开发,而基类所具有的公共界面成为派生类的共有界面的一个子 集。C++允许设计者选择类的基类是共有的或私有的。如果基类是共有的,则其共有界面将 成为新的派生类的共有界面部分,这表明基类的行为成为派生类的行为部分。这类似于类型 与派生类型之间的关系。如果基类是私有的,它的行为将不是继承类的公共行为部分而是实 现部分。它的提出是为了提供实现新类的服务。 ⑧ 抽象类 :某些语言提供了一个类,用它做为继承结构的开始点,所有用户定义的类 都直接或间接以这个类为基类。Smalltalk 提供了一个类 Object 做为所有类的继承树的根,而 C++则支持多重继承结构。每一种结构都包含了一组类,它们是(或应该是)某种概念的特殊 化。这个概念应抽象地由结构的根类来表示。因此,每个继承结构的根类应当是目标概念的 一个抽象模型。这个抽象模型生成一个类,它不用于产生实例。它定义了一个最小的共有界 面,许多派生类可以加到这个界面上以给出概念的一个特定视图。 (3) 通过复用设计类 利用既存类来设计类,有 4 种方式:选择,分解,配置和演变。这是面向对象技术的一 个重要优点。许多类的设计都是基于既存类的复用。 ① 选择 :设计类最简单的方法是从既存构件中简单地选择合乎需要的构件。这就是开 发软件库的目的。一个 OO 开发环境应提供常用构件库,大多数语言环境都带有一个原始构 件库(如整数、实数和字符),它是基础层。任一基本构件库(如“基本数据结构”构件)都应 建立在这些原始层上。这些都是些一般的和可复用的类。这个层还包括一组提供其它应用论 域服务的一般类,如窗口系统和图形图元。表 6.1 显示了建立在这些层上面的特定域的库。 最低层的论域库包括了应用论域的基础概念并支持广泛的应用开发。特定项目和特定组的库 包括一些论域库,它包含为相应层所定义的信息。 表 6.1 一个面向对象构件库的层次 特定组的构件 ─ 一个小组为他们自己组内所有成员使用而开发 特定项目的构件 ─ 一个小组为某一个项目而开发 特定问题论域的构件 ─ 购自某一个特定论域的软件销售商 一般构件 ─ 购自专门提供构件的销售商 特定语言原操作 ─ 购自一个编译器的销售商 ② 分解 :最初标识的“类”常常是几个概念的组合。在设计时,可能会发现所标识的 操作落在分散的几个概念中,或者会发现,数据属性被分开放到模型中拆散概念形成的几个 组内。这样我们必须把一个类分成几个类,希望新标识的类容易实现,或者它们已经存在。 ③ 配置 :在设计类时,可能会要求由既存类的实例提供类的某些特性。通过把相应类 的实例声明为新类的属性来配置新类。例如,一种仿真服务器可能要求使用一个计时器来跟 踪服务时间。设计者不必开发在这个行为中所需的数据和操作,而是应当找到计时器类,并 在服务器类的定义中声明它。 ④ 演变 :要开发的新类可能与一个既存类非常类似,但不完 全相同。此时,不适宜采用“选择”操作,但可以从一个既存类演 变成一个新类,可以利用继承机制来表示一般化-特殊化的关系。特 殊化处理有三种可能的方式。 ▪ 由既存类建立子类 :现要建立一个新类“起重车”。它的 许多属性和服务都在既存类“汽车”中。关系如图 6.13 所示。新类 是既存类的特殊情形。这时直接让“起重车”类作为“汽车”类的子类即可。 汽车类 起重车 类
②建立继承层次由既存类建立新类:现要增加一个新类“拖拉机”。它的属性与服务 有的与“汽车”类相同,有的与“汽车”类不同。关系如图614所示。这时,调整继承结构 建立一个新的一般的“车辆”类,把“拖拉机”与“汽车”类的共性放到“车辆”类中,“拖 拉机”与“汽车”类都成为“车辆”类的子类。“车辆”是抽象类,相关操作到子类“汽车” 类去找 车辆 汽车类 汽 拖拉枳 拖拉机类 图6.14调整继承结构 ③建立既存类的父类:另一种情形是想在既存类的基础上加入新类,使得新类成为既 存类的一般类。例如,已经存在“三角形”类,“四边形”类,想加入一个“多边形”类, 并使之成为“三角形”和“四边形”类的一般类。继承结构如图6.15所示。从这个“多边形” 类又可派生出新的类,如“六边形”类。 多边形 三角形类)多 形 四边形类)类 四边形 六边形 图6.15建立一般类 后两种涉及既存类的修改。在这两种情况下,既存类中定义的操作或数据被移到新类中 如果遵循信息隐蔽和数据抽象的原理,这种移动应不影响已有的使用这些类的应用。类的界 面保持一致,虽然某些操作是通过继承而不是通过类的定义伸到这个类的 (4)类设计方法 通常,类中的实例具有相同的属性和操作,应当建立一个机制来表示类中实例的数据表 示、操作定义和引用过程。这时,类的设计是由数据模型化、功能定义和ADT定义混合而 成的。类是某些概念的一个数据模型,类的属性就是模型中的数据域,类的操作就是数据模 型允许的操作。要明确规定它们两个谁先确定是不可能的,两个处理是互补的。 类的标识有主动和被动之分。被动类是数据为中心的,它们是根据系统的其它对象发送 来的消息而修改其封装数据的:主动类则提供许多系统必须履行的基本操作。与被动类的实 例(被动对象)一样,主动类的实例(主动对象)接收消息,但这些对象是负责发送追加消息和 控制某些应用部分的。在窗口环境,一个窗口是一个被动对象,它基于发送给窗口的消息来 显示某些内容。窗口管理器是一个主动对象,它担负着各种在它控制的窗口上的操作。 在被动类与主动类的设计之间不存在明显的差别。在设计主动类时,需要优先确定数据 模型,稍后再确定操作;在设计被动类时,把类提供的服务翻译成操作。在标识了服务之后 再设计为支持服务所需要的数据。许多类都是这两个极端的混合。 类中对象的组成包括了私有数据结构、共享界面操作和私有操作。而消息则通过界面 执行控制和过程性命令。因此,要分别讨论它们的实现 类的设计描述包括两部分: 14
14 ② 建立继承层次由既存类建立新类 :现要增加一个新类“拖拉机”。它的属性与服务 有的与“汽车”类相同,有的与“汽车”类不同。关系如图 6.14 所示。这时,调整继承结构。 建立一个新的一般的“车辆”类,把“拖拉机”与“汽车”类的共性放到“车辆”类中,“拖 拉机”与“汽车”类都成为“车辆”类的子类。“车辆”是抽象类,相关操作到子类“汽车” 类去找。 图 6.14 调整继承结构 ③ 建立既存类的父类 :另一种情形是想在既存类的基础上加入新类,使得新类成为既 存类的一般类。例如,已经存在“三角形”类,“四边形”类,想加入一个“多边形”类, 并使之成为“三角形”和“四边形”类的一般类。继承结构如图 6.15 所示。从这个“多边形” 类又可派生出新的类,如“六边形”类。 图 6.15 建立一般类 后两种涉及既存类的修改。在这两种情况下,既存类中定义的操作或数据被移到新类中。 如果遵循信息隐蔽和数据抽象的原理,这种移动应不影响已有的使用这些类的应用。类的界 面保持一致,虽然某些操作是通过继承而不是通过类的定义伸到这个类的。 (4) 类设计方法 通常,类中的实例具有相同的属性和操作,应当建立一个机制来表示类中实例的数据表 示、操作定义和引用过程。这时,类的设计是由数据模型化、功能定义和 ADT 定义混合而 成的。类是某些概念的一个数据模型,类的属性就是模型中的数据域,类的操作就是数据模 型允许的操作。要明确规定它们两个谁先确定是不可能的,两个处理是互补的。 类的标识有主动和被动之分。被动类是数据为中心的,它们是根据系统的其它对象发送 来的消息而修改其封装数据的;主动类则提供许多系统必须履行的基本操作。与被动类的实 例(被动对象)一样,主动类的实例(主动对象)接收消息,但这些对象是负责发送追加消息和 控制某些应用部分的。在窗口环境,一个窗口是一个被动对象,它基于发送给窗口的消息来 显示某些内容。窗口管理器是一个主动对象,它担负着各种在它控制的窗口上的操作。 在被动类与主动类的设计之间不存在明显的差别。在设计主动类时,需要优先确定数据 模型,稍后再确定操作;在设计被动类时,把类提供的服务翻译成操作。在标识了服务之后 再设计为支持服务所需要的数据。许多类都是这两个极端的混合。 类中对象的组成包括了私有数据结构、共享界面操作和私有操作。而消息则通过界面, 执行控制和过程性命令。因此,要分别讨论它们的实现。 类的设计描述包括两部分: 汽车类 拖拉机类 车辆 汽车 拖拉机 四边形类 多 边 形 类 多边形 三角形 四边形 六边形 三角形类
①协议描述:协议描述定义了每个类可以接收的消息,建立一个类的界面。协议描述 由一组消息及对每个消息的相应注释组成。 ②实现描述:实现描述说明了每个操作的实现细节,这些操作应包含在类的消息中。 实现描述由以下信息构成: 类名和对一个类引用的规格说明 私有数据结构的规格说明,包括数据项和其类型的指示 每个操作的过程描述 实现描述必须包含充足的信息,以提供在协议描述中所描述的所有消息的适当处理。由 个类所提供服务的用户必须熟悉执行服务的协议,即定义“什么”被描述;而服务的提供 者(对象类本身)必须关心:服务如何提供给用户,即实现细节的封装问题。 5.对象模型技术 Rumbaugh等人提出对象模型技术(OMT,它把分析时收集的信息构造在三类模型中 即对象模型、功能模型和动态模型。图6.16给出了这三个模型的建立次序。从功能模型回到 对象模型的箭头表明,这个模型化的过程是一个迭代的过程。每一次迭代都将对这三个模型 做进一步的检验、细化和充实 对象模型 动态模型 图6.16对象模型、功能模型和动态模型的建立次序 (1)对象模型 对象模型是三个模型中最关键的模型,它 实例 的作用是描述系统的静态结构,包括构成系统 (类名) 正方形 的类和对象,它们的属性和操作,以及它们之 属性 属性值 边长 间的关系。事实上,这个模型可以看作扩充的 位置 实体一关系模型(E一R)。图6.17给出了在对 边框颜色 填充颜色 象模型中用以表示类和对象的图形符号。在 OMT中,类与类之间的关系叫做关联。关联 擦图 代表一组存在于两个或多个对象之间的、具有 相同结构和含义的具体连接。关联可以是物理 的,也可以是逻辑的 图6.17类与对象的表示方法 图6.18给出与关联有关的几个特殊图形符号。 句子(上图) 聚合 类A[限定词 B 目录 ]这作幻一 句子(中图) AtE 名字 名字(下图 角色 角色 雇主 职务雇员 的表示方法和实
15 图 6.17 类与对象的表示方法 ① 协议描述 :协议描述定义了每个类可以接收的消息,建立一个类的界面。协议描述 由一组消息及对每个消息的相应注释组成。 ② 实现描述 :实现描述说明了每个操作的实现细节,这些操作应包含在类的消息中。 实现描述由以下信息构成: ▪ 类名和对一个类引用的规格说明 ▪ 私有数据结构的规格说明,包括数据项和其类型的指示 ▪ 每个操作的过程描述 实现描述必须包含充足的信息,以提供在协议描述中所描述的所有消息的适当处理。由 一个类所提供服务的用户必须熟悉执行服务的协议,即定义“什么”被描述;而服务的提供 者(对象类本身)必须关心:服务如何提供给用户,即实现细节的封装问题。 5. 对象模型技术 Rumbaugh 等人提出对象模型技术(OMT),它把分析时收集的信息构造在三类模型中, 即对象模型、功能模型和动态模型。图 6.16 给出了这三个模型的建立次序。从功能模型回到 对象模型的箭头表明,这个模型化的过程是一个迭代的过程。每一次迭代都将对这三个模型 做进一步的检验、细化和充实。 图 6.16 对象模型、功能模型和动态模型的建立次序 (1) 对象模型 对象模型是三个模型中最关键的模型,它 的作用是描述系统的静态结构,包括构成系统 的类和对象,它们的属性和操作,以及它们之 间的关系。事实上,这个模型可以看作扩充的 实体-关系模型(E-R)。图 6.17 给出了在对 象模型中用以表示类和对象的图形符号。在 OMT 中,类与类之间的关系叫做关联。关联 代表一组存在于两个或多个对象之间的、具有 相同结构和含义的具体连接。关联可以是物理 的,也可以是逻辑的。 图 6.18 给出与关联有关的几个特殊图形符号。 图 6.18 关联的表示方法和实例 对象模型 动态模型 功能模型 类 实例 示例 类名 属性 操作 正方形 边长 位置 边框颜色 填充颜色 画图 擦图 移动 (类名) 属性值 整体 聚合 部分 段落 句子 类 A 限定词 类 B 目录 句子 (上图) 文件名 (中图) 类 A 类 B 关联 角色 角色 公司 名字 名字 个人 (下图) 工作 职务 工资 雇主 雇员