对象 是数据和相关行为的集合。我们如何区分不同类型的对象呢?苹果(Apple)和橘子(Orange)都是对象,但很显然苹果和橘子不是同一类对象。苹果和橘子在计算机编程中并不常用,但让我们假设现在在为一个农场开发库存软件。为了方便描述下面的示例,我们可以假设用 桶 ( Barrel )装苹果,而用 篮子 ( Basket )装橘子。
我们要解决的问题到目前为止涉及4种对象:苹果、橘子、篮子和桶。在面向对象建模中,用 类 ( class )来描述对象的种类。所以,从技术上讲,我们现在有4个类。
理解类和对象的区别是很重要的。类描述了相关的对象。它们就像创建对象的蓝图。你面前的桌子上可能放着3个橘子,每个橘子都是不同的对象,但这3个橘子都是橘子类,都拥有橘子类的属性和相关行为。
对于库存软件中4个类的关系,可以用 统一建模语言 (简称 UML )的类图表示。这是我们的第一个类图,如图1.1所示。
图1.1 类图
图1.1表明 Orange 类的实例(通常被称为orange)和 Basket 有某种关联, Apple 类的实例(通常被称为apples)和 Barrel 有某种关联。关联是类的实例之间最基本的关系。
UML图的语法浅显易懂。你在看到一张图的时候,通常不需要阅读说明文档就能理解它的意思。UML图也很容易绘制,很自然。毕竟,很多人在描述类和类的关系时,会自然地画出矩形,并用线条把它们连起来。在这种自然的图表基础上制定一个标准,有利于程序员与设计师、管理人员互相交流,也有利于程序员之间互相交流。
值得注意的是,UML图通常描述的是类定义,但类定义也描述了对象的属性。图1.1中包含了Apple类和Barrel类,表明一个特定的apple被放在某一个barrel中。我们也可以用UML图描述单个对象,但这基本没必要。通过类图足以说明对象之间的关系,因为对象是类的成员。
有些程序员认为使用UML是浪费时间。他们认为在迭代开发中,包含UML图的正规设计说明书是多余的,直接实现就行了。而且,维护这些UML图只会浪费时间,没什么用处。
任何多于一个人的开发团队都偶尔需要坐下来讨论一下正在开发的组件的细节。UML图对于确保快速、简单和一致的沟通是极其有用的。就算那些嘲笑正规类图的团队也会在其设计会议和团队讨论中使用一些草图,这些草图相当于“山寨版”的UML图。
此外,你必须要与之沟通的最重要的人是将来的自己。我们都认为自己会记住当初的设计决定,但将来几乎总会出现这样的时刻:我当时为什么这么干?如果我们保留了最初设计时画的图表,最终会发现这些是很有用的参考。
然而,本章并不是关于UML的教程。网上有很多关于UML的教程,也有很多这个主题的书。UML包含的不仅是类图和对象图,还包含用例图、部署图、状态图和活动图。在讨论面向对象设计时,我们会用到一些常见的类图的语法。你可以先从示例中学习它们的结构,然后自然而然地将其用到你的团队和个人的设计中。
我们最初的类图是正确的,但没有告诉我们apple要放在barrel中,也没有明确一个apple是否可以放在多个barrel中。它只是告诉我们apple和barrel有某种关联。类之间的关联通常是显而易见的,不需要额外的解释,但在必要时,我们可以添加额外的解释来进一步澄清。
UML的美在于大部分的东西都是非必需的。我们只需要在图中画出对当前设计有价值的信息。在一个快速会议上,我们可能只需要在白板上画出一个个用线连起来的矩形。而在一个正规的文档中,我们可能需要更多的细节。
在apple和barrel的示例中,它们之前的关系很明显是 多个apple可被放在一个barrel 中。但为了防止有人认为一个 barrel只能放一个apple ,我们可以完善一下类图,如图1.2所示。
图1.2通过一个小箭头告诉我们Orange被 放在 Basket中,它还告诉我们这个关系两边的对象各自的数量。一个 Basket 可以包含多个(用*表示) Orange 对象。任何一个 Orange 只能被放在一个 Basket 中。这个数字被称为对象的多重性,你也可能听到它被称为基数。我们可以将基数理解成一个具体的数字或范围。在这里用多重性*表示多于一个的实例。
图1.2 有更多细节的类图
你有时候可能会忘记一个关系中的哪个边应该用哪个多重性数字。与类距离最近的多重性表示那个类的对象的数量,它们可以与关系另一端的任意一个对象关联。对于apple被放入barrel的关联,从左往右读,很多 Apple 类的实例(就是很多 Apple 对象)可被放入任意一个 Barrel 。从右往左读,一个 Barrel 可以与任意一个 Apple 关联。
我们已经掌握了类的基础知识,以及它们如何定义对象之间的关系。现在我们需要讨论定义对象状态的属性,以及对象的行为,对象的行为可能导致状态改变或与其他对象交互。