1.9.3 第2阶段:我们将如何建立对象
在这一阶段,我们必须做出设计,描述这些类和它们如何交互。确定类和交互的出色技术是类职责协同(Class-Responsibility-Collaboration, CRC)卡片。此技术的部分价值是它非常简单:只要有一组3到5英寸的空白卡片,在上面书写。每张卡片描述一个类,在卡片上写的内容是:
(1) 类的名字。这很重要,因为名字体现了类行为的本质,所以有一目了然的作用。
(2) 类的职责:它应当做什么。通常,它可以仅由成员函数的名字陈述(因为在好的设计中,这些名字应当是描述性的),但并不产生其他的注记。如果需要开始这个过程,请从一个懒程序员的立场看这个问题:你希望有什么样的对象魔术般地出现,把你的问题全部解决?
(3) 类的协同:它与其他类有哪些交互?“交互”是非常宽泛的术语。它可以是一些已经存在的其他对象对这个类的对象提供的服务。协同还应当考虑这个类的观众。例如如果创建了Firecracker(鞭炮),那么谁将观察它,是Chemist(药剂师)还是Spectator(观众)?前者希望知道鞭炮由什么化学成分组成,后者对鞭炮爆炸后的颜色和形状有反应。
我们可能想让卡片更大一些,因为我们希望从中得到全部信息,但是它们是非常小的,这不仅能保持我们的类小,而且能防止过早地陷入过多的细节。如果一张小卡片上放不下类所需要的信息,那么这个类就太复杂了(或者是考虑过细了,或者应当创建多个类)。理想的类应当一目了然。CRC卡片的思想是帮助我们找到设计的第一印象,使得我们能得到总体概念,然后精炼我们的设计。
CRC卡片的最大的好处之一是在交流中。在一个组中,最好实时进行交流,而不是用计算机。每个人负责几个类(起初它们没有名字或其他信息)。每次只解决一个情节,决定发送什么消息给不同的对象以满足每个情节,这样就能作出一个比较形象的对问题的模拟。当我们经历了这个过程后,就会找出我们所需要的类以及它们的职责和协同,这样,我们同时也填写好这些卡片。当我们完成所有用例后,就有了一个相当完整的设计的第一印象。
在我开始用CRC卡片之前,当提出最初的设计时,我最成功的咨询经验就是站在一个没有OOP经验的项目组前,在白板上描述对象。我们讨论对象应当如何互相通信,擦除其中的一些,用其他的对象替换它们。实际上我是在白板上管理所有的“CRC卡片”。项目组(他们知道项目的目标)真正地在做这个设计,他们“拥有”这个设计,而不是获得既成的设计。我所做的所有事情就是通过提问正确的问题,提炼这些假设,并且从项目组得到反馈,修改这些假设来指导这个过程。这个过程的真正好处是项目组学习了如何做面向对象的设计,不是通过复审抽象的例子,而是通过在一个设计上工作,这对于他们是最有兴趣的。
制作了一组CRC卡片之后,我们可能希望用UML创建这个设计的更形式化的描述。我们并不是非要用UML,但它可能有帮助,特别是如果我们要将一个图表挂在墙上,让大家一起思考时,这是一个很好的想法。除了UML之外的另一选择是对象及其接口的文字描述,这或许依赖于我们的程序设计语言,也就是代码本身。
UML还提供了另外一种图形符号来描述系统的动态模型。在一个系统或子系统的状态转换占主导地位,以至于它们需要自己的图表的情况下,这是有帮助的(例如在控制系统中)。我们可能还需要描述数据结构,因为系统或子系统中数据结构是重要因素(例如数据库)。
当已经描述了对象及其接口后,第2阶段就要完成了。这时已经知道了对象中的大多数,通常会有对象漏掉,直到第3阶段才被发现。这没问题。我们关心的是最终能找到所有的对象。在这个阶段较早地发现它们是好的。因为OOP提供了充分的结构,所以如果我们稍迟发现它们也可以。事实上,对象设计可能在程序设计全过程的五个阶段中都会发生。