作者:温昱
中国人喜欢用“瓶和酒”作为“形式和内容”的隐喻,没想到老外也有同样的思维方式。《定位》一书的作者说:“糖罐在放上糖之前只是个空罐;同理,词语在人们使用它并赋予
它意义之前是没有含义的。”语言的语法和语义,就是这样一种“瓶和酒”、“罐和糖”关系。
UML是可视化建模语言的工业标准,在业界已经被广泛应用。和其他所有语言一样,UML也对思维具有反作用——是促进思维还是阻碍思维,全凭UML的使用者对UML内涵的掌握程度了。《定位》的作者说过:“有些人玩不好定位游戏,因为他们太依赖字面意义。”同样,要想玩好UML“游戏”——达到UML促进思维的境界——也必须将UML语法和UML语义紧密结合。
承接上篇,本文继续结合实例来说明图论思想在UML应用中的意义,希望能对读者有所启发。
一、着色顶点
在图论的基本理论中,有加权顶点的概念。顶点具有的与之相关的数,称为权(weight);该顶点称为加权顶点。
这里我们做个扩充,引入着色顶点的概念:顶点具有的与之相关的颜色,称为着色(color);该顶点称为着色顶点。
举个例子,讨论图的定义时的图,现在每个顶点都被着了色。着色顶点可以表达更为丰富的含义:比如在本图中,红色、蓝色和黄色的顶点可以分别代表大、中、小型城市,边代表它们直接的直达航班;从中型城市V1到中型城市V6,没有直达航班,要在大型城市V4转乘,一目了然。
二、着色顶点的UML应用——通过颜色为图元分类
用UML为问题及解决方案建模的时候,有时UML图会比较复杂,不容易读懂。下面以两个例子来说明如何运用着色顶点的方法,提高UML图的易读性。
下图是J2SE集合类框架的UML图,运用了蓝、黄两种彩色。每个看这幅UML图的人,在留意众多细节之前,都会首先注意到本图的大局——多个蓝色的类组成的层次结构,周围分布着一些黄色的类。继续看下去,蓝色的类和黄色的类之间使用的是“实现”关系——于是知道黄色的类是接口。至此,整个结构清楚了——多个具体类组成了类层次结构,不同的具体类可能实现特定接口。接下来,分析该UML图的语义细节……
再举一例。下图试图为整个软件工程学科建立概念模型,涉及到的图元比较多,概念也比较复杂,所以使用了黄、红、绿、蓝等多种彩色。实际上,上述四种颜色分别代表过程、项目管理、方法论、任务四个子范畴;一方面,这些色彩的含义要大致读懂了该UML图之后,才能反映到读者的脑海中;另一方面,其实在读者看图过程中,这些色彩就起了很大作用了——它们将一幅比较大的类图划分成四个相对独立的小区域,使读者看起图来有条不紊。
建模的本质是抽象,抽象的目的是把握重点,以使结构清晰化。如果我们画的UML图太复杂,那就应当想一想,我们是不是犯了“为建模而建模”的毛病,忘记了原本的目的呢?
使UML图清晰易读的方法有很多,为图元着色就是其中一种,并且它是令人愉快的。仔细想来,上面两例都是用颜色为图元分类,这种分类带来了两条令人兴奋的好处:其一,为原图附加了一层大局信息,这些大局信息会被读者最先注意到,并为进一步理解图的细节打下基础;其二,由于大局信息是通过着色的方式提供的,并没有引入任何新的图元,所以图的复杂性并没有增加。
三、着色顶点的UML应用——UML彩色建模方法介绍
如果问我,看完《人月神话》这本书,给我印象最深的一个词是什么,我会毫不犹豫地回答:概念完整性。为了达到概念完整性,领域建模(domain modeling)是非常重要的一个环节。可喜的是,领域建模已经越来越被业界所重视,也有不少好书和好的方法浮出水面。本节介绍Peter Coad大师的著作《Java Modeling In Color With UML: Enterprise Components and Process》中讲述的彩色建模方法——一种领域建模方面的优秀技术。
Peter Coad认为,领域模型主要由四种元素组成,它们分别是:瞬间事件(MomentInterval)、角色(Role)、人-物-地点(PartyPlaceThing)、描述(Description)。彩色建模技术的目的是“为模型增加一层‘视觉可监测的’信息”,具体而言,它定义了四种颜色分布标识上述四种领域元素。
粉红:代表“瞬间事件”。在模型中,瞬间事件往往封装了我们最感兴趣的方法(method),这些方法和系统将来的功能有直接的联系,它们可以说是模型的灵魂。它们也是最容易变的,因此选用了最活跃的粉红色代表。
黄色:代表“角色”。瞬间事件的发生,往往会牵涉到多个角色,角色具体由“人-物-地点”来扮演。角色意味着在特定场景下的责任,它们也是比较容易变化的,但比起瞬间事件还是要稳定些,所以用比较活泼的黄色代表。
绿色:代表“人-物-地点”。业务领域不同,会牵涉到不同的人、物、地点。它们都比较稳定,用安静的绿色表示。
蓝色:代表“描述”。最后为人、物、地点引入更抽象一级的描述元素,这些描述元素可以被多个不同的“人-物-地点”所共享。比如Date就是描述元素,人可以有生日,汽车可以有生产日期,等等。描述是最为稳定的一类模型元素,用稳定得几乎忧郁的蓝色代表。
好了,举个例子吧。下图是网管软件领域建模时的模型之一角。Ping是瞬间事件元素,其涉及两个角色元素:Pinger和Pingee。这两个角色都由IPDevice来扮演,IPDevice属于“人-物-地点”元素。IPDevice拥有零到多个IPAdress,IPAdress是描述元素。当然,IPDevice和其四个子类Router、Switch、Server和Host都是“人-物-地点”元素。
Edward R. Tufte在其经典著作《Envisioning Information》中指出,颜色在信息设计中的基本作用有四:
分类
度量
模仿
装饰
彩色建模方法充分利用了颜色的分类和度量功能(当然经过颜色装饰的模型也比原来更赏心悦目):它不仅利用了四种颜色来为图元分类,而且粉红、黄、绿、蓝四种颜色分别代表不同等级的“易变程度”,具有度量意义。
由于篇幅所限,以上只是对彩色建模方法的简单介绍,感兴趣的朋友还是找书来看看吧。
四、着色边
在上文中,我们对经典图论进行了小小扩充,并且体会了这种扩充的应用价值。接下来,我们对边的概念进行类似的扩充——着色边。
边具有的与之相关的颜色,称为着色(color);该边称为着色边。
五、着色边的UML应用——标识良性依赖与恶性依赖
合理处理依赖关系,是“拥抱变化”的关键所在。在《拥抱变化:敏捷设计从理论到实践》(《程序员》2004年第11期)一文中,笔者阐述了敏捷设计的理解基础:良性依赖原则。不会“在实际中”造成危害的依赖关系,都是良性依赖;依赖的“理论危害”不一定成为“实际危害”,反之亦然。这就是良性依赖原则。
那么,如果能使用着色边的方法,将依赖的良、恶性可视化,对软件设计人员无疑是大有裨益的。我们规定:
良性依赖用绿色表示;
恶性依赖用红色表示。
例如,敏捷设计大师们提倡的“通过重构得到设计模式”,在着色边方法的帮助下,变得易于理解,并且极具可操作性;其步骤如下:
1. 使用最简单的设计,完成当前的功能。此时,往往是类之间的直接调用,但由于功能需求也简单,所以类之间的依赖关系也往往是良性依赖。
2. 当需求有所变化或增加时,首先考察原先的设计是否可以直接支持新需求;如果可以通过直接增强某个类来达到目的,但是原先的良性依赖也随之变成了恶性依赖,那就应当否定这种方案,而去做第3步的重构。
3. 通过重构改变原先的设计,使新的设计为支持新需求做好准备,且保证依赖关系都是良性依赖。
4. 在新设计的基础上,增加新功能的支持。这时你往往会发现,哇,设计模式出现了。
下面举例。为了突出着色边方法给“通过重构得到设计模式”带来的可操作性,我们再来看看(上)篇的那个例子:需求跟踪矩阵工具,其最初的需求是支持项目以专有格式保存,后来,又要求能够导出成HTML格式的网页。下面的四幅设计类图都运用了着色边方法,它们概括了整个设计变化的过程:
1. 最初的设计。符合敏捷设计的简单性原则。
2. 考察老设计在新需求下的情况。CProjectSaver要支持多种保存策略,违反了单一职责原则。
3. 重构得到的新设计。很好的设计,但对最初的需求而言,却是过度设计(over-engineering)。
4. 在新设计之上添加新功能。就是策略(strategy)模式呀。
通过上面的例子可以看出,着色边方法在某种程度上,将设计的依据“可视化”了,因此为设计人员带来了方便。
六、图的同构
称图G与图H同构,如果
(1) 存在V(G)与V(H)的一一对应;
(2) 存在E(G)与E(H)的一一对应;
(3) 在(1)与(2)的一一对应保持顶点与边的关联关系不变。
比如下面两个UML类图,其语义是完全相同的。
七、图的同构的UML应用——UML风格
互为同构的UML图,其语义虽然是完全相同的,但其易读性,却可能相差极大。因此,我们提倡好的UML风格。
下图是一幅UML状态图,描述了Java线程的状态变化情况。该图的起始点在最左边,终止点在最右边,始态和终态分别在次左边和次右边,整个图结构清晰,语义一目了然。
再看这幅图,语义完全相同,但是看起来却费劲多了。
这里不再举更多例子了,《UML风格》一书,汇集了很多绘制UML图的专家级建议,值得一读