?备注:本篇偏向面向对象基础知识,可以略过。
??????
? ? ? ?面向对象的系统因为很好的原因在计算机行业变得越来越普遍。面向对象的系统比传统的过程式系统更模块化、更易于维护,也更容易描述。由于可视化工具包是使用面向对象设计进行设计和实现的,我们在本章中致力于总结面向对象设计和实现的概念和实践。
????????当今的软件系统试图解决复杂的现实世界问题。严格的软件设计和实现方法可以减轻这种复杂性带来的负担。没有这样的方法论,软件开发人员可能会发现很难满足系统的规格要求。此外,随着规格的变化和增长,一个没有坚实的基础架构和设计的软件系统将难以适应这些不断增加的要求。
????????我们的可视化系统是需要考虑可扩展性的复杂软件的一个很好的例子。数据可视化是一个快速扩展的领域,每年都会推出可视化技术。任何希望整合未来创新的系统必须具有支持添加新内容而对现有系统影响不大的基础设计。
????????面向对象设计是一种软件工程方法,它能够舒适地处理复杂性,并为以后的变化和添加提供框架。面向对象设计过程试图将一个复杂的任务分解成称为对象的小而简单的部分。对象是计算机抽象,用来模拟系统中被模拟的物理或抽象部分。面向对象设计方法提供机制来识别系统中存在的抽象,并对对象的行为进行建模。
????????软件设计的质量很难衡量,但一些定性方面可以指导我们。良好的软件设计应该是健壮的、可理解的、可扩展的、模块化的、可维护的和可重用的。
????????健壮的系统能够优雅地处理异常情况,并且行为一致。健壮性给软件开发人员带来信心,即系统的基本组件将如预期般地行为,即使在比原始实现者预期的情况下使用系统时也是如此。
????????可理解的系统可以被除了原始实现者以外的其他人使用。系统的使用应该是合乎逻辑和合理的。系统组件的名称应该来自问题领域。
????????可扩展的系统在执行原始预期的任务的同时接受新的任务。系统应该接受新形式的数据和新的算法,而不会破坏现有的软件。向系统添加一个新的基本部分不应该导致系统的大部分被修改。经验表明,在系统中修改的现有代码越多,引入错误的可能性就越大。
????????模块化的软件系统最小化系统组件之间的关系数量。紧密耦合的系统组件应该在逻辑上分组,并遵守共同的命名约定和协议。
????????软件维护在系统设计过程中经常被忽视。然而,系统的总成本包括维护和原始开发。如果问题很容易被隔离,并且修复一个问题不会在系统的无关部分引入问题,那么软件系统就是可维护的。
????????最后,软件开发的经济性要求我们尽可能地利用过去的工作。在理想的情况下,在现有系统中实现新技术应该是一项简单的任务。这在软件系统中很少见。创建可重用的软件组件可以减少工作的重复,并在系统内促进一致的接口。然而,正如我们在本书中所看到的,创建可重用的软件通常需要额外的努力。一个人的短期生产力观念与软件开发组织的长期生产力观念存在冲突。
????????对象是面向对象系统中的主导概念。对象是抽象,它封装了系统中实体的属性和行为。每个对象都有一个标识,用来区分它和系统中的其他对象。通常,对象的可区分方面是显而易见的。例如,在计算机桌面上,一个窗口与另一个窗口的区别可能是颜色、位置、大小或内容。但是,外表可能具有欺骗性,即使两个对象具有完全相同的特征,它们仍然可能具有不同的标识。两辆汽车可能具有相同的制造商、型号、选项和颜色,但仍然是两辆不同的车。现实世界通过车辆识别号来区分这两辆车。同样,处理多个实体的编程系统需要一个标识机制。在数据库系统中,一组标识键(称为 n-元组)标识系统中的实体。
????????但是,面向对象系统与传统的过程式编程系统有何不同呢?主要的区别在于这两种方法处理数据抽象的方式。传统系统将抽象限制为数据类型,而面向对象系统为数据和可以应用于数据的操作创建了抽象。事实上,面向对象系统将数据和操作一起保存在一个编程构造体中,称为对象。数据和操作共同构成了对象的属性。当对对象应用操作时,编程语言的动态绑定机制执行适用于该对象的过程。这在过程式系统中并不是这样。程序员必须提供逻辑来决定调用哪个过程。处理多种类型的系统通常充斥着用于选择操作适当过程的 case 语句。随着这些系统添加新类型,调度基于数据类型的操作的代码必须扩展以处理新类型。例如,在一个用于显示不同类型基本部件的程序中,以下伪代码显示了过程式系统与面向对象系统的不同之处。
????????过程式(用 C 语言):
?
Primitive *aPrim;
...
DrawPrimitive (aPrim)
...
procedure DrawPrimitive (aPrim)
{
if (aPrim->type == TRIANGLE) then DrawTriangle (aPrim)
else if (aPrim->type == SQUARE) then DrawSquare (aPrim)
else if (aPrim->type == CIRCLE) then DrawCircle (aPrim)
...
}
? ? Object-oriented (in C++):
...
aPrim->Draw ();
...
????????在项目的后期,有人可能想要添加一个新的基元,比如说一个二次方程。负责这项艰巨任务的人必须搜索现有系统,找到第一个示例中所有 if 语句的出现,并为新的二次方程类型添加一个测试。当然,一个优秀的程序员会将代码隔离到一个位置,就像我们在这里做的一样,所以任务会更容易一些。然而,那个程序员必须首先意识到原始程序员足够有技巧地将绘图代码模块化,然后找到代码(不一定知道过程名)并修改代码。使事情复杂化的是,由多名程序员构建的系统无疑会处于配置管理系统之下,需要进行检出、编辑和检入循环。
????????面向对象的程序员有一个更容易的任务。查阅定义了基元对象属性的设计文档,这个程序员为二次方程对象添加了一个绘制操作。在不改变任何现有代码的情况下,新的基元就可以被系统使用!当然,这是一个过于简化的例子。但是想想你过去写过的程序,回想一下添加新的数据类型有多么困难。你的更改是被隔离到你添加的新代码吗?你是否不得不编辑你没有编写过甚至可能不理解的代码?在阅读我们关于数据可视化库的面向对象实现之前,请记住这个例子。
????????在更详细地描述面向对象设计和编程之前,我们提出一个观察和预测。在过去的几年里,我们使用面向对象方法设计和实现软件,我们观察到新手对这种技术会说:“但这就是我已经写程序的方式。我的系统是模块化的;它们是健壮的;我可以轻松地为它们添加功能。”如果在阅读本书之后你仍然有这种感觉,不要归咎于面向对象的方法。相反,我们作为作者可能失败了。然而,这种消极的回应是不太可能的。根据我们的经验,用户在很短的时间内就会适应这种方法。特别是当他们通过一个现有的、设计良好的面向对象系统来介绍对象时。你会达到“啊哈”阶段,之后很难开始一个软件项目而不去寻找问题中的对象。
????????与任何软件工程设计方法一样,面向对象设计有自己的术语。不幸的是,并不是每个人都同意这些术语是什么。我们从 Rumbaugh [Rumbaugh91] 和 Stroustrup [Stroustrup84](由于可视化工具包是用 C++ 编写的)那里采用了大部分术语。在很大程度上,Rumbaugh 的术语是独立于编程语言的,而 Stroustrup 则是特定于 C++ 实现。从设计到编程的过渡将是毫不费力的,两种术语之间的映射大多是显而易见的。在我们认为可能会引起混淆的地方,我们会指出对应关系。
什么是对象?
????????对象是一个抽象,它模拟系统中实体的状态和行为。抽象是一种提取特定目的下情况的基本方面的心智过程。实体是系统中具有标识的事物。椅子、飞机和相机是对应于现实世界中物理实体的对象。二叉树、符号表和有序集合是仅存在于计算机科学世界中的对象。
????????图 2-1 是当我们将系统组件的状态和行为映射到对象时发生的抽象的一个例子。在这里,对象是一种特定类型的树:柏树。在这个应用程序中,我们希望模拟各种类型的树在一个季节内的生长。为了我们的目的,我们决定重要的状态变量是树的年龄、树干直径、高度和习性(即生长形态)。为了捕捉柏树的行为,我们有方法来模拟生长和对应于春季、夏季、秋季和冬季的季节效应。还有一些方法(未显示)用于设置和获取当前状态变量。
????????图 2-1. 将现实世界对象映射到对象抽象。现实世界的对象是各种类型的树。其中一个对象(一棵柏树)被映射到我们称之为 PinOak 的计算机对象中。
我们称对象的状态为其属性(也称为实例变量),并通过可以应用于它的操作来定义其行为。属性具有名称、数据类型和数据值。属性的数据类型可以是编程语言中的原始类型(如 C++ 中的 char 或 float),也可以是另一个对象。例如,我们的可视化系统中的 vtkTransform 对象具有一个类型为 vtkMatrix4x4 的属性。vtkMatrix4x4 又具有作为 float 值在 C++ 中声明的原始值数组的属性。
????????操作是可以应用于对象的函数或变换。操作定义了对象的行为。特定对象的操作是在我们称为方法的过程中实现的。
????????对象的属性和操作共同构成其属性。一个二维线图可能具有的属性包括 x 轴和 y 轴、图例以及一组相连的点。这个图表有绘制图表在窗口中的方法。它还有方法让用户指定轴、要绘制的数据和要使用的图例。
????????共享相同属性的对象可以使用分类过程进行分组。对象类,通常称为类,指定了该类中所有对象具有的属性。类仅指定属性的名称,而不是它们的具体值。不同的类可以(通常也会)具有其他类中存在的属性名称。我们可视化系统中的许多类都具有一个名为 Position 的属性。尽管我们的可视化系统中的相机和演员都具有这个属性,但因为它们是不同的类,所以对每个类的影响是不同的。属性名称由给定类中的所有对象共享,但为每个对象的属性值分配了单独的存储空间。
????????当相同名称的操作应用于不同类的对象时,我们称该操作为多态的。例如,我们的可视化系统有一个名为 Render() 的操作,可以应用于许多不同的对象。特定类的操作的实现称为方法。vtkMatrix4x4 对象的打印操作是在其打印方法中实现的。也就是说,存在知道如何打印 vtkMatrix4x4 类对象而不是其他类对象的代码。对象知道要使用哪个方法,因为它们保存在每个对象的数据结构中。在大多数系统中,同一类中所有对象的方法的代码是共享的。一些编程语言,包括 C++,通过将操作名称与其参数类型结合来定义方法。这个过程称为操作重载,是一种允许使用相同名称进行逻辑上相似的操作的强大技术。例如,下面的类定义了三种计算一个数字的平方的方法。尽管这些方法具有相同的操作名称,但它们是唯一的,因为 C++ 同时使用操作名称和操作参数类型。
class math
{
? float square(float x);
? int square(int x);
? double square(double x);
}
要使用类的成员进行某种目的,我们创建一个类的实例(实例化的过程)。实例创建建立了实例的身份,包括指定其初始状态。实例的类在创建期间充当实例的模板,定义了每个属性和操作的名称。创建建立了这个实例与同一类的其他实例之间的相似性和差异性。相似性是其属性的名称和类型以及实现其操作的方法。差异是属性的具体值。如何创建类的实例的细节因编程语言而异。在 C++ 中,程序可以使用声明形式创建一个实例,比如
vtkActor aBall;
这将从程序堆栈中创建一个对象,或者通过应用 new 操作
vtkActor *aBall = new vtkActor;
这将从程序堆中创建对象。
????????继承
????????继承是一种编程机制,当需要从当前已存在的类中以微小方式区别时,可以简化向系统中添加新类的过程。继承的概念源自这样一种观察:大多数系统可以使用分层分类系统来指定。地球上生命的分类体系是一个很好的例子。
????????早些时候,我们创建了一个对应于柏树的对象。使用继承可以更彻底地描述树的属性(图 2-2)。这里显示的分类是基于 Margulis 和 Schwartz [Margulis88] 的五界系统。在这个系统中,生物被分类为五个界:原核生物界(细菌)、原生生物界(藻类、原生动物和粘菌)、真菌界(蘑菇、霉菌、地衣)、植物界(苔藓、蕨类、裸子植物和种子植物)和动物界(有脊椎动物和无脊椎动物)。在这个级别以下,我们有分类:门、纲、目、科、属和种。图中显示了柏树的界、门、纲、属和种。
????????将对象组织成继承层次结构有许多好处。一般分类的属性也是其子分类的属性。例如,我们知道橡树属的所有物种都形成橡子。从软件角度来看,这意味着超类的任何实例变量和方法都会自动被其子类继承。这使我们能够通过修改它们的超类同时对多个对象进行更改。此外,如果我们希望将新类(比如红橡树)添加到层次结构中,我们可以这样做,而无需复制现有功能。我们只需要通过添加新的实例变量或重载现有方法来区分新类与其他类。
????????图2-2。油橡树的继承层次结构。
????????能够快速添加与当前现有类略有不同的新类,促进了系统的可扩展性。继承可以通过称为专门化的过程自上而下派生,也可以通过称为泛化的过程自下而上创建,将类似的类组合在一起。使用继承意味着存在一个或多个类的类层次结构,其中一个或多个子类是其超类。子类继承其超类的操作和属性。在C++中,子类称为派生类,超类称为基类。子类可以添加额外的操作和属性,修改其从超类继承的属性。通过这种继承,对象可以展示其超类的行为以及它希望的任何附加行为。它还可以限制或覆盖其超类实现的操作。
????????仅用于充当其子类超类的类称为抽象类。通常禁止创建抽象类的实例。抽象类用于收集所有子类将使用的属性和方法。它们还可以为其子类定义行为协议。这是继承的强大用途,将出现在我们可视化系统的设计中。抽象类可以强制执行复杂的序列控制协议,并确保统一的行为。它们将复杂协议的责任从各个子类中移除,并将协议隔离在超类中。
????????一个简单绘图包的示例展示了抽象类的强大之处。考虑一个数据展示应用程序,允许各种二维绘图。这个应用程序必须支持折线图、水平和垂直条形图。设计过程确定了所有绘图共有的属性,包括标题、坐标轴和图例。然后,我们创建一个名为TwoDPlot的抽象类来包含这些共有属性。常见的行为也可以在TwoDPlot中的plot方法中捕获:
?
Method Plot
{
Draw the border
Scale the data
Draw the axes
Draw the data
Draw the title
Draw the legend
}
????????抽象类可以为每个操作提供默认行为,也可以不提供。在这个例子中,可以提供边框和标题绘制的默认行为。然后,TwoDPlot的子类将为其他方法定义自己的函数。协议规范明确说明了TwoDPlot的子类应该响应的方法。在上面的例子中,子类将需要为绘制坐标轴、数据和图例定义自己的方法。一些子类可能使用TwoDPlot的方法来绘制边框,其他子类可能需要他们自己版本的这个方法。在TwoDPlot中定义的抽象接口使得更容易添加新的2D绘图类,由此产生的子类往往更加统一和一致。
????????另一个机制,委托,用于隔离和重用行为。使用委托,一个对象将操作应用于其属性之一,该属性是一个对象。例如,在可视化工具包中,vtkTransform对象将其Identity()操作委托给其vtkMatrix4x4属性。然后,vtkMatrix4x4的实例执行该操作。还有许多有用的面向对象概念,但目前我们已经有足够的信息来描述如何使用对象来设计一个系统。
????????任何大型软件系统的设计都是一项艰巨的任务,系统设计的第一步通常是最具挑战性的。无论我们选择什么设计技术,我们都必须对系统的应用领域有透彻的了解。设计一个飞行控制系统,没有对底层硬件控制系统的详细了解是很困难的。当然,并非所有的飞行系统软件都是由航空工程师设计的,因此必须存在某种形式的系统规范。规范中的信息深度因应用而异。
????????面向对象的系统设计始于建模步骤,从问题陈述或软件需求规范中提取对象及其与其他对象的关系。首先,设计者必须完全了解正在解决的问题。这通常需要对问题领域有深入的了解或者能够获取问题解决的详细规范。然后,必须在系统内部识别主要的抽象。在这一设计的高层次上,这些抽象将成为第一组对象。例如,一个跟踪投资组合的系统将需要股票、债券和共同基金等对象。在计算机动画系统中,我们可能需要演员、摄像机和灯光。医用计算机断层扫描系统将有一张桌子、X射线源、探测器和回转体。我们的可视化系统将有模型、等值面、流线和剖面。在这个建模步骤中,我们搜索对象、属性和关系的问题领域。稍后,在设计的多次经过中,模型将被扩展。
????????建模是大多数设计过程中的一步,无论我们是设计船舶、房屋、电子系统还是软件。每个学科都遵循一种使用专门创建的技术来使设计过程高效和有价值的方法论。这些技术被称为“行业工具”。电气工程师使用原理图和逻辑图,建筑师使用图纸和模型,造船者使用比例模型。同样,软件设计师需要可以帮助创建系统模型的工具。这些软件工具应该具有足够的表现力,以帮助软件设计师评估设计是否符合规范,并帮助将设计传达给软件团队中的其他人。
????????我们使用了由吉姆·朗保和他的同事在GE开发的对象建模技术(OMT)[Rumbaugh91]。OMT使用三种模型来指定面向对象的设计:对象模型、动态模型和功能模型。每个模型描述系统的不同方面,每个模型都有相应的图表技术,帮助我们分析、设计和实现软件系统。
????????对象模型
????????对象模型识别系统中的每个对象,其属性以及与系统中其他对象的关系。对于大多数软件系统来说,对象模型占据主导地位。OMT图形技术使用矩形来描述对象类,并使用各种连接器来描述继承和其他对象之间的关系。对象类以实心矩形表示。实例以虚线矩形表示。类或实例的名称位于矩形的顶部。一条线将类名与包含属性的下一部分分开;第三部分描述了方法。对象之间的关系用连接两个相关对象的线段表示。在OMT中,关系称为关联,它们可以具有各种基数:一对一、一对多和多对多。表示其他对象的容器的特殊关联称为聚合。关联可以带有角色标签。(角色是分配给关联的名称,用于进一步描述关联的性质。)OMT使用三角形表示继承,超类连接到三角形的顶点,子类连接到三角形的底部。图2-3显示了虚拟现实系统中定位设备的对象模型。
????????类层次结构中的第一个对象是定位器。这个抽象类指定了所有定位器的共同属性和方法。定位器的子类是locator2D和locator3D。在这个对象模型的当前版本中,定位器只有一个属性,一个设备和两个方法,open()和close()。定位器的两个子类locator2D和locator3D也是抽象类,包含区分它们的属性和方法,这些属性和方法基于它们的空间维度。例如,locator3D具有x、y、z位置,而locator2D具有x、y位置。这两个定位器都有一个locate()方法,用于更新当前位置。在3D定位器类中,locate()还会更新方向。locator3D的子类包括来自三个不同制造商的硬件:flock、pixsys和logitek,以及一个关节定位器的抽象类。硬件的三个对象类包含特定于每个设备的方法。每个方法知道如何转换设备返回的特定硬件代码。它们知道要被视为locator3D子类,它们必须实现一个位置和方向操作,该操作将提供x、y、z坐标和可以组成转换矩阵的三个角度旋转。对象模型还向我们展示了关节定位器具有角度和连杆。两个特定的关节定位器是immersion和phantom。以这种方式绘制的对象模型图作为设计和讨论的起点。它展示了共同的方法和属性,以及每个类的区别特征。
????????稍后,在实施过程中,我们将把这些对象模型转换成软件对象。我们选择的特定计算机语言将决定转换的细节。
图2-3. 定位设备的对象模型。
????????动态模型
????????对象模型描述了系统的静态部分,而动态模型详细描述了系统的事件序列和时间依赖性。OMT使用状态图来建模系统动态。动态模型经常用于设计控制系统和用户界面。我们的可视化系统具有有限的序列和控制方面,因此我们不会深入讨论状态图。但是,如果我们要为数字手表设计用户友好的界面,图2-4中的状态图将会有用。
????????图中的椭圆显示了一个状态;箭头显示了从一个状态到另一个状态的转换;箭头上的标签显示了导致状态转换的事件。这个例子显示了三个显示状态和多个设置状态。事件b1表示按下按钮一。这块手表有三个按钮。图表显示了在每个状态下当这三个按钮中的任何一个被按下时会发生什么。图表清楚地显示了b1用于在时间、日期和闹钟之间切换显示模式。B2从显示模式转换为设置模式,或者选择要在给定模式下更改的字段。B3递增所选字段一个单位。状态图还显示了当按下非法按钮时会发生什么。如果手表显示时间,按下按钮3时,不会发生任何事情。如果手表显示闹钟,按下按钮3时,将切换闹钟的开/关状态。
功能模型
????????功能模型显示数据如何在系统中流动,以及过程和算法如何转换数据。它还显示了过程之间的功能依赖关系。暴露这些关系将影响对象模型中的关联。数据流图(DFD)的主要组件是数据源、数据汇和过程。数据源和数据汇被表示为矩形。椭圆表示过程。数据存储显示在两条水平线之间。DFD对于描述系统中的整体流非常有用。它们也可以用来描述将一个数据表示转换为另一个数据表示的任何过程。在功能建模过程中识别的过程可能在对象模型中出现为操作或对象。
????????图2-5显示了一个3D医学成像系统的数据流图。图表显示了计算机断层扫描(CT)或磁共振成像(MRI)扫描仪上的数据采集。扫描仪提供的一系列横截面切片首先通过图像处理滤波器处理,以增强灰度切片中的特征。一个分割过程识别组织并为切片中存在的各种组织产生标签。然后,这些带有标签的切片通过表面提取过程传递,以创建位于每种组织表面上的三角形。渲染过程将几何形状转换为图像。或者,写入过程将三角形存储在文件中。稍后,可以读取这些三角形并将其渲染成图像。我们将推迟决定是否将这些过程转换为对象或操作,直到以后。第4章使用DFD来建模可视化管道。
????????图2-5. 数据流图。
????????计算机编程语言的选择是一个信仰问题。每种计算机语言都有其布道者和追随者。我们在面向对象语言方面的大部分经验都是用C和C++。C本身没有面向对象的功能,但面向对象的方法论和严格的编码指南允许开发面向对象的代码。我们选择C++作为可视化工具包的实现语言,因为它内置了对类的概念、方法动态绑定和继承的支持。C++在许多UNIX平台和个人计算机上也广泛可用。
????????Simula[Birtwistle79]通常被认为是第一种面向对象语言,但Smalltalk[Goldberg83]可能是最知名的语言。Smalltalk是在七八十年代在施乐帕罗奥多研究中心(PARC)开发的。Smalltalk不仅提供了一种语言,还提供了一个使用对象构建的操作系统和编程环境。当你使用Smalltalk时,你就是在生活和呼吸对象。对于面向对象纯粹主义者来说,没有什么能替代Smalltalk。Smalltalk的衍生版本包括窗口系统、工作站和桌面范例。苹果电脑和微软都承认Smalltalk和施乐PARC对麦金塔和Windows的影响。Smalltalk可能是在商业上广泛接受的时候提前了10年。在Smalltalk的初期和青少年时期,软件的复杂性远远低于今天的系统。FORTRAN服务于科学和工程界,COBOL是商业应用的选择,计算机科学界则拥抱了C语言。抽象概念的运用仅限于数学家和其他抽象思维者。编程被视为一种艺术形式,程序员们专注于算法的巧妙实现。每个新任务通常需要一个新程序。技术程序员确实使用数值库进行常见的数学运算,但在更高层面上对共同抽象的概念相对较少。
????????不要低估设计系统所需的投入。尽管面向对象技术有巨大潜力产生良好的软件设计,但这些技术并不能保证良好的设计。我们在本文中介绍的可视化系统植根于我们在10年间开发的动画[Lorensen89]和可视化系统[Schroeder92]。最初的设计确定了用于工业应用计算机动画的25个类,这个设计由四名软件专业人员花费了10个月的时间(近3.5人年)才完成。在这个设计阶段,开发人员没有编写任何代码。随后的实施只花费了一个月,或者说是总工作量的十分之一。即使在其他20名软件开发人员为系统增加了500多个类之后,这个系统仍然为我们的可视化小组提供服务。原始的25个类至今仍存在于系统中。
????????作为读者,我们希望您能从我们在可视化系统设计方面的经验中受益。我们试图通过在每章的“将所有内容放在一起”部分描述可视化工具包类的属性(属性和方法)来帮助您。还包括一系列由Doxygen文档系统生成的对象图,这些图将为您快速概述对象关系,如超类和子类。这些文档可以在CD-ROM上或者在线找到,网址是http://www.vtk.org。在下一章中,我们还将解释我们做出的决定,以设计VTK面向对象工具包。
????????本章介绍了面向对象的概念和术语。重点是处理复杂性以及面向对象技术如何提供机制来减少软件的复杂性。
????????模型构建是任何设计方法论的重要组成部分。我们介绍了三种模型和符号。对象模型描述了系统中的对象及其静态关系、属性和方法。对象图简洁地呈现了这些静态信息。动态模型侧重于系统的时间相关方面。状态转换图用于模拟系统的序列和控制部分。功能模型显示了系统中对象如何转换数据或其他对象。数据流图是显示功能依赖关系的方便符号。
如今有几种面向对象的实现选择。虽然可以在非面向对象语言(如C语言)中实现面向对象系统,但最好选择面向对象语言来服务方法论。我们选择了C++来实现可视化工具包。
????????本书的重点是架构、数据结构设计和算法。系统的面向对象方面很重要,但系统的功能更为重要。
????????有几本关于面向对象设计的优秀教材。[Rumbaugh91]和[Birtwistle79]都介绍了与语言无关的设计方法论。这两本书强调建模和绘图作为设计的关键方面。[Meyer88]也描述了在Eiffel(一种面向对象语言)背景下的面向对象设计过程。另一本流行的书是由Booch [Booch91]所著。
????????任何想要成为面向对象设计和实现的严肃用户都应该阅读Xerox Parc的Smalltalk开发人员所著的Smalltalk书籍[Goldberg83] [Goldberg84]。在另一本早期的面向对象编程书籍中,[Cox86]描述了面向对象技术和Objective-C编程语言。Objective-C是C语言和Smalltalk的混合体,Next Computer在实现其操作系统和用户界面时使用了它。
????????有许多关于面向对象语言的书籍。CLOS [Keene89]描述了通用列表对象系统。Eiffel是一种强类型的面向对象语言,由[Meyer88]描述。Objective-C [Cox86]是一种弱类型语言。
????????由于C++已成为一种流行的编程语言,现在有许多类库可用于应用程序。[Gorlen90]描述了一个大量类集合和数组的类库,模仿了[Goldberg83]中描述的Smalltalk类。[Stepanov94]和[Musser94]描述了标准模板库,这是ANSI C++标准的一部分,包含了数据结构和算法框架。Open Inventor [Inventor]是一个支持交互式3D计算机图形的C++库。Insight分割和注册工具包(ITK)是一个相对较新的类库,通常与VTK [ITK]一起用于医学数据处理。VXL是一个用于计算机视觉研究和实现的C++库[VXL]。还有许多其他C++工具包,如VNL(VXL的一部分)和Blitz++ [Blitz]等数学库也可用。各种其他C++工具包都可以通过Google搜索 [Google]找到。
????????C++书籍不胜枚举。C++的作者[Stroustrup84]所著的原始描述是任何严肃的C++程序员必读的?