UML自1997年诞生以来,受到无数厂商、组织、专家学者的追捧和拥护,短短几年时间,便有一统天下之势。提起建模语言,舍UML其谁? UML相关标准 OMG组织作为影响力最大的面向对象技术的机构,早早便将UML收入囊中,力捧其为标准建模语言。OMG在CORBA取得成功之后,最大的着力点便是MDA架构,而MDA架构的四大标准UML、MOF、XMI和CWM中,围绕着UML的技术便有三种:UML本身自不必说,版本已经到了2.0;MOF作为“建模语言的语言”,似乎就是为UML量身定做的,虽说MOF有能力创建出与UML并驾齐驱的建模语言,但是似乎没有看到谁这么干,大家只是在努力的发展UML的“方言”,例如UML Profile for CORBA,UML Profile for EJB等等;XMI是“模型的标准存储交换格式”,为了解决不同的建模工具创建的模型不能互用的问题,OMG创建了XMI作为模型的存储交换标准。这样一来,UML工具更加可以大行其道,使用不同的建模工具创建的UML模型可以互相交流,只要它们都基于XMI。 UML相关工具 工具的多寡与优劣可以看出某个技术的受欢迎程度,在建模工具中,不说100%,大概也有90%支持了UML语言。最出名的UML工具Rational Rose,被IBM收购了;Eclipse下面的UML工具EclipseUML让开发它的小公司Omondo也出名了;国内也有一个UML工具,听说效果也不错,就是楚凡科技的Trufun Plato 2005。至于其他国际上有点名气的UML工具,更是不胜枚举,几乎有点软件实力的国家,都有自己的UML工具。 当然,UML不仅仅出现在专用的UML工具中,它也频繁出现在最新的各种开发环境中。例如编程开发环境JBuilder,具有将代码转换为UML类图的功能;Together就更进一步,直接实现了代码和类图的同步转换;Eclipse作为最优秀的开放式开发平台,拥有众多的UML相关插件,除了前面提到的EclipseUML,比较有名的还有EMF和UML2。 UML在MDA出现之后,在OMG的概念中,成为了MDA的一个子集(虽然UML的名气远远大于MDA)。因此众多的MDA工具中,几乎都少不了UML功能。我认为很多MDA工具就是从UML工具直接改过来的。 UML使用现状 照理说来,如火如荼的标准和工具应该催生出如火如荼的应用才对,可是UML的使用状况实在不尽如人意。无论是身边的还是网络上的朋友,在项目中使用UML的都是凤毛麟角,即便使用了UML,也是在很小的范围内,完全没有发挥出1%的功效。现在总结一下目前我所知道的UML使用现状:
- 读代码时,用UML工具进行逆向工程,可以清晰的观察代码结构,方便理解代码。
- 写代码时,由于开发平台可以自动生成UML类图,因此有时观察UML类图得到比较清晰的代码结构。例如Together或者JBuilder等工具。当然,如果没有自动生成的UML图,大部分人也不会寻找其他工具去生成UML类图的。
- 撰写科技论文时,使用UML来表达系统架构或者系统流程等。
- 部分对UML非常熟悉的程序员,在开始写代码时,先画UML类图,然后利用工具生成代码,最后对代码进行扩展。
从上面的使用现状可以看出,很多人把UML当成一种可有可无的技术。即使使用了UML,也只是围绕着UML中的类图,其他的UML图都抛到一边去了。造成这种状况的原因,一方面固然是因为国内的正规大型软件项目比较少,软件工程技术起步很晚;另一方面是由于国内不管是架构师、系统分析员、软件工程师、程序员、测试人员等等实质上都是程序员而已,很多人是赶着鸭子上架成了架构师或者系统分析员的。这种状况下,软件工程的概念难以深入人心,UML更加成了一个国内项目的鸡肋。 看看国外的架构师、UML专家们,往往都是满脸大胡子,在计算机领域中浸淫了3,40年;而中国最古老的程序员,也只有十几年经验,除去在黑暗中摸索的几年,有十年以上开发经验的程序员少之又少。不经历几个大型项目,要使用软件工程技术是不可能的,也是不能起到什么效果的。因此,有人堂而皇之的撰文“UML的三大硬伤”,将UML驳斥得一无是处。高喊口号打倒某东西是很容易的,关键是打倒了UML何以取而代之? 程序员眼中的UML 既然国内90%以上的软件开发人员都是程序员,那么程序员眼中的UML到底应该是什么样子的呢?我很期望有一本好书能够让程序员们快速的掌握自己所需的UML知识,遗憾的是目前还没有看到这样的一本书。无论是“三友”的UML经典教材还是国内的一些“xx天精通UML”都不符合这样的要求。没有一本是“有中国特色的UML教材――一本写给程序员的UML入门书”。 作为一个程序员,我很了解其他同僚的心理,如果拿到一本书,翻了一个小时还没有找到可以run的HelloWorld,90%的人会大叫一声“去nmd”,然后把书扔进废纸堆。不能怪我们急功近利,在这个技术术语满天飞,连底层平台都动荡不安的年代,谁还有时间和兴趣看一些与自己无关的东西呢? 我很能想象一个程序员,好不容易空出时间来看看最近很热的UML技术,当他拿到一本UML入门以后,开始寻找对自己有用的东西。在开始的一个小时,满篇都是需求分析,use case,甚至书的作者还在饶有兴趣的介绍use case有六种译法:用例、用况、用案……对不起,老子一百年都没做过需求分析了,也不想知道这个狗屁的use case到底叫什么。于是开始后悔在china-pub上又白花了这么多银子。 还有些书上信誓旦旦的说“学好UML,走遍天下都不怕”,如果你做需求分析,你可以用UML和客户交流;如果你做系统分析员,你可以用UML设计系统;如果你做程序员,你可以用UML生成程序;如果你做测试员,你可以基于UML设计测试用例。而实际情况是什么呢?国内的客户有几个懂UML?懂UML的人差不多自己都可以把软件写出来了,还需要请你做需求分析么?别说客户了,上次听同学说和北京某大科研所的工程师们交流,无意中说起了UML,在场的竟然只有一个稍微了解,而且坚持认为那是一种画图工具(那位仁兄其实也没错,Visio不就是一个画图工具么)。 虽然状况如此不堪,但是UML确实是一个很优秀的“交流语言”、“代码生成工具”和“系统设计工具”。让我们擦干身上的献血,掩埋战友的尸体,睁大迷蒙的双眼来看清UML对程序员的作用。UML有九种图,作用各自不同,基本上涵盖了软件工程的各个方面,很多人就是不堪于忍受知识不足的困惑与“侮辱”(很多程序员认为一种技术自己看不懂就是对自己的侮辱),从而放弃了整片UML森林。他们怕的不是在UML这棵树上吊死,而是怕在UML森林里面迷路。但是我想说,知识学习的过程就是去芜存精,找出对自己有用的东西,然后掌握之。对于程序员来说,UML的价值就体现在三个方面: 一、UML是最好的交流语言,无论是与其他程序员交流,还是与领域专家、测试员或者用户交流。原因只有一点,UML是标准的,就像英语一样,无论多么该死,大家还是忙着把自己的论文改成英文的。当然,在小的领域可能有更好的交流方言,但是在大而长远的交流中,使用标准的交流语言是稳妥的。 二、UML是很好的代码生成工具,其实代码生成功能并不是由UML语言和规范提供的,而是由UML工具提供的,而且不同的UML工具提供的代码生成功能还不尽相同。例如Rose提供简单的代码框架生成,而Eclipse插件EMF可以生成功能丰富,提供了各种设计模式的代码包。无论如何,如果程序员可以从UML入手来写程序,比直接敲代码要高级那么一点点。从文档、版本控制、维护、测试等各方面来说,画UML类图比直接写代码都要高那么一点点。 三、UML是很好的系统设计工具。对于程序员来说,很少用到“设计”这个词,大部分时候我们都是在“编写”或者“实现”。但是勿庸置疑,程序员的许多工作中还是需要“设计”的。包和组件之间的依赖关系、复杂操作的流程、对象之间的关联和状态、程序的部署等等,都经常是程序员的工作。那么上面的四种情况可以用UML的组件图、序列图、对象图和部署图来设计。虽然,不同的程序员有不同的设计方法或者设计图例,不过,UML是标准的。不要忽视标准的力量,标准的东西意味着在全世界范围内都有可能会被看懂,不标准的东西可能出了你的办公室就没人能够清晰、准确的理解了。 后记 Blog好久没有更新,因为最近一直忙于一些俗物,于是想写点清高的东西。但是写完之后再看,好像也不怎么清高,反而更俗了。 前段时间写论文时,需要用到UML2.0的类图元模型,在UML2.0的规范中寻觅了好久,发现类图元模型已经被拆分到三个包里面了,因为UML2.0的规范实在是太大太繁琐了。于是有感于UML之博大精深,说好听是博大精深,难听点就是乱七八糟。不过OMG历来如此,当初的CORBA如果更简约一点,也许J2EE根本就没有立足之地。 感慨之后就是想把UML中对自己有用的部分整理出来,在整理之前免不了到处翻资料,这篇文档就是翻资料的一些感触了。希望能够将UML的有用部分都整理出来,形成一个系列的文档。 克服用例图的恐惧 在实际工作中,大部分程序员很少接触到需求分析,即使有需求分析,也是草草了事,没有用正规的方式来表达,所以一般程序员使用用例图的机会是不多的。但是却又常常在各种媒体上看见用例图,于是对一种常常出现,自己又不太熟悉的技术,会产生恐惧。如果说对MDA或者CORBA这样的技术产生恐惧还是值得的话,对用例图产生恐惧是非常不值的。因为MDA和CORBA这样的技术也许要花上半年的时间才能够初步了解,而克服用例图恐惧症,则只要不到一天的时间。 用例图初感 UML是一组图示符号的标准。所谓图示符号,就是一组定义好的图示,它们可以表达定义好的各种意思。用UML进行软件建模,就是用规定好的符号画图,这些图表达了开发人员脑中的软件系统。用UML进行软件建模,其难度并不比我们小时候上的美术课更难。在美术课上,一个圆形加上四根线条表示太阳,一个三角形加上一个矩形表示房子;同理,在UML的用例图中,一个椭圆表示用例,一个小人表示参与者。我并不认为它们之间有质的区别,想到我对这种小学生画图课恐惧了几年,不由得感到羞愧。 用例图是UML的九个图中较为重要和常用的一种图。常常用于软件开发的需求分析阶段,也能用于软件的系统测试阶段。简单的来说,用例图是描述系统的外部视图。 在开始设计一个软件系统时(更广义的情况下,可以用来设计任何系统),需要一种手段来发现系统的功能,用例图虽然是图示,但是这些图示隐含了一种启发系统功能的手段。其实所有的UML图都只包含图示和标准,并不包含方法,但是它们往往隐含了某种方法。UML和软件开发方法的关系,很类似于汉字和语文的关系。 用例图包含了三种基本的概念:用例、角色和系统。它们可以组合起来表达系统的外部视图。而且这种表达方式是如此直观和简单。 第一张用例图 画用例图是一件很简单的事情,而且感觉还很舒适,因为用例图简洁、直观。虽然用例图不能像HelloWorld一样运行,也不能生成代码,不过画一张清晰的用例图还是很有成就感的。 我使用的工具是Eclipse+EclipseUML插件,功能不如Rose,但是是开源而且免费的(EclipseUML有free版也有企业版),而且效果也不错。第一张用例图如下: 可以看出图中有一个系统(保险商务系统),两个角色(客户和保险销售员)以及三个用例(签订保险单、销售统计资料、客户数据资料),另外还有四个连接线以及一个注释。如果在纸上或者合适的工具中,画这样一张用例大概只需要五分钟吧。不过仅仅画出来是没有意义的,需要弄清楚其背后真正的含义才行。 理解用例图 可以这样简单的理解用例图中的一些概念,系统(System)指的是软件系统,它可以包含一些用例,并界定系统的边界,边界之内的属于系统的功能和行为,边界之外的则不是系统所关心的内容。系统规定了一个具有某些功能的黑盒子,在系统之外看到的仅仅是这个系统的功能,而不能看到系统的内部细节。这一点也是用例图经常被用来做系统测试的原因。当然这些测试一般是黑盒测试。 角色(Actor)是与系统中的用例交互的一些实体,在实际情况中,角色可以是人,也可以是其他系统或者硬件设备。在画用例图的过程中,角色往往是第一个被确定的,因为系统或者用例在开始时是模糊的,但是参与系统的角色是最容易明晰的。有了角色之后,根据角色与系统的交互,以及角色要求的功能,可以进一步确定系统和用例。 用例(Use case)指的是系统的功能,它是系统某个功能的所有执行动作的集合。在UML图示中它是一个椭圆,但是具体分析用例的时候需要给出这个用例的所有执行动作的步骤。例如上图中的“签订保险单”用例,就可以分为几个步骤:第一,客户发出保险单请求;第二,系统给出保险单样式表;第三,用户填写保险单样式表;第四,系统检查用户提交的保险单格式是否规范;第五,如果不规范则返回第二步,如果规范则给保险单销售员发出消息;第六,保险单销售员填写保险单;第七,保险单销售员将填写好的保险单加入数据库,并将客户资料输入客户数据库。当然,以上步骤仅仅是我想象的,我还从来没有见过什么“保险单”,这次过了一把瘾。 连接(Assocation)是角色与用例的连接,表达此角色可以初始化此用例。 注释(Note)可以添加到任何地方,对用例图的不同部分加以说明。 泛化、包含和扩展 泛化(Generalization)在面向对象的技术中无处不在,它的另一个名字也许更为著名,就是“继承”。下图给出了一个使用泛化的用例图: 由此可知,在用例图中,角色和用例都能够泛化。角色的泛化/继承很容易理解,因为角色本来就是类(Class),它是一种版型(stereotype)为Actor的类,所以角色的继承直观而自然。但是用例的继承实际上分为两种情况,并不是简单的使用泛化,而是使用扩展(extended)和包含(include)两种泛化的特例。 扩展用于子用例的动作步骤基本上和父用例的动作步骤相同,只是增加了另外的一些步骤的情况下。包含用于子用例包含了所有父用例的动作,它将父用例作为了自己的一个大步骤,子用例常常包含一个以上的父用例。如下图: 小结 关于用例图基本上也就是上面提到的这些内容了。当然,用例图还常常和类图、活动图联合使用,不过那些知识还是等其他知识完备了以后再说比较好。 我总结的画用例图的步骤如下:
- 确定系统,拟出系统的名称,这个不难,例如电信计费系统;
- 找出所有与系统打交道的角色,角色要进行一些精简和整合;
- 站在角色的立场想象系统应该提供的功能,将这些功能画成系统中的用例;
- 对于每个用例给出详细的动作步骤;
- 找出用例图中角色、用例之间可能有的继承、扩展或者是包含关系;
以我现在的理解能力,认为用例图到此为止了。当然,我还可以想象,用例图会用来启发类图的构建,例如用例图中的某些部分(角色或者用例)会变成类图中的类或者接口。另外,可以想象用例图还可能会影响活动图中的流程。 后记 让我恐惧了好久的用例图在今天便土崩瓦解了,心中却彷佛有一点茫然,因为我记得自己无数次的对自己说“好忙啊,这个技术肯定要花很多时间,还是以后再学吧”类似的话。当我用C的时候对C++这样说过,然后是Java、CORBA、JSP、XML、MDA、XMI、UML…… 写blog不仅仅是一种爱好,对我来说,更是一种最好的学习方法,当我读小学的时候,班主任常常对我说“好记性不如烂笔头”,我当时的理解是把事情用笔记下来比用脑袋背下来更加持久(脑袋是内存?纸笔是数据库?)。但是,现在我理解到,要学习某个东西,最好的方法是用自己的语言把它表达出来,如果你能让别人理解这个技术,你自己当然已经精通了。在我写blog的过程中,常常会出现写到一半的时候猛然领悟的情况,这是因为当你在选择最佳的表达方式的时候,将你自己头脑中一团乱麻的线索都理清了的结果。 有朋友留言说,自己计算机本科毕业,在计算机领域学习了八年,竟然看不懂我的blog。这个我认为很正常,读本科的时候,所有同学都可以在一起讨论问题、实习;等到上研的时候,同学对我说他的课题,我只能模糊的听个大概,因为专业方向已经分开了;现在读博了,同学要拉着我说他的课题,我只能明白是哪个领域里面的问题,往往对这个问题的描述都听不懂了。这是因为研究方向已经非常精细的原因。我自问我的方向已经很大众化了,如果研究图像压缩算法的话,那满篇都是数学公式了;如果研究微电子技术,那么满篇都是集成电路图了。 还有一点,如果我感兴趣的技术在网上已经能够找到很好的资源,那么我不会动笔去写blog了,我会把资料下载到硬盘就好了。例如XML技术,我的blog中只有两篇,第一篇是“XML的本质讨论”,总结出了别人看不到的XML本质,提出了一些新观点;第二篇是“XSL:转换从哪里开始”。其实XML技术浅显易懂,我也有很多感想和心得,不过其中只有XSL在网上不能找到很好的总结资料,因此我写了那一篇。这也是我坚持原创和创新的一点反映吧。对于那种狂贴别人资料的blog,我是不以为然的。我只喜欢原创或者第一手翻译资料的blog。 类图,就是比你高一点 UML的成功80%是因为类图,提到UML的时候有90%的人想到了类图,应用UML的时候100%应用了类图。如果类图和源代码走到一起,肯定是要代码抗钉耙的,因为论武功和智慧,类图都高了那么一点点。 乱谈类图 如果说程序是一个人,那么类图就是这个人的躯体。也就是说,光有类图,一个程序已经成型了,看上去很像那么一回事了。UML在刻画程序的静态结构方面很成功,但是在刻画程序的动态语义时很失败,至今没有一个好的解决方案,或者说,没有一个能让各方面都接受的方案。如果UML动态语义的问题解决了,那么MDA的目标就真的达到了,模型可以完全代替代码了。 目前的MDA工具,号称模型代码同步的,号称代码生成的,号称PIM/PSM转换的,大部分都只是和类图打交道罢了。因为类图和代码之间的转换是如此自然,以至于出现了Together这样的工具,模型(类图而已)和代码是同步的。 类图是程序的躯体,动作语义才是程序的灵魂,可惜UML在刻画程序灵魂的事情上做得太不出色了。很多研究者仅仅把目光放在类图上,类图到代码的生成几乎已经没有什么可以研究了,还是抱住不放,在生成的代码中加入约束、加入设计模式、加入持久化存储等等。怒其不争、哀其无志。想到自己也是其中的一员,不由临表涕零。 类图难点问题总结 类图是非常容易学习的,因为它和面向对象编程是孪生兄弟,如今的程序员哪有不懂面向对象的,因此类图对于他们,就如同奶瓶对于婴儿一般。下面从硬盘中翻出一幅曾经自己画的类图,相信大家一看便知: 类图是一门易学难精的技术,正如面向对象技术一样,一百个程序员九十九个都说自己懂面向对象,但是真正入门的可能不到十个,真正精通的也许只有一个,这个人还往往不是中国人,唉~ 自己重新学习UML的动机就来自于一次论文撰写过程中,想查阅类图的元模型图,但是问遍同行,翻遍网络,找不到合适的图形或者描述,最后只能求救于OMG的UML规范。一查之下,大惊失色,原来很多东西原来都是懵懵懂懂,不甚了了。因此痛下决心,要弄懂类图中的疑点。 翻看类图,我发现有如下是疑点所在:
- Attribute和Property的关系如何?区别和共同点是什么?
- 完整的描述一个操作(Operation),需要多少东西?
- 类之间可以有关系(Relationship),关系可以是关联(Association)或者泛化(Generalization),这个你知道么?
- 关联有七种:普通关联、递归关联、限定关联、或关联、有序关联、三元关联、聚合(聚合和组合),各自有什么含义?用法如何?
- 关联类(Association Class)的含义如何?应用场景如何?
- 类的实例化是对象,关联的实例化是什么呢?
总结出了这些疑点要归功于中文UML书籍的模糊和混乱,或者是翻译者的语焉不详。所以让我在复习时找出了这么多的疑点。 要查阅资料,解决疑难,并举例说明,起码需要3,4天的时间,因此这篇随笔就作为类图的引文先发了。也希望志同道合者和我一起研究上面的问题。 后记 周末了,想偷懒了,结果适得其反,刚刚完成这篇blog就停电了,后面的几百字全没了。这一点告诉我们,持久化存储是多么重要啊~ 类图释疑之一,Attribute和Property之区别 上一篇中提出了很多问题,其中最令人费解的可能就是Attribute和Property之区别了吧。我在网络上寻找良久也没有发现好的解释,反而发现了很多混乱的解释和用法。因此,依靠OMG网站上的UML规范以及自己的理解,整理出了这篇文章。 UML中的Attribute和Property之区别 在很多人的脑海中,Attribute就是类的属性,Property呢?好像也是类的属性?因此有很多人不加区别的统一称为类的属性,尤其是在写中文文章的时候。这种心理是典型的鸵鸟心态,眼不见为净。其实稍微用脚想一下就知道,事实肯定不是这样的,UML中既然发明了这两个术语,显然不是用来冗余的。它们之间肯定有着千丝万缕的联系与区别。 各种各样的面向对象语言、各种组件技术、模板技术、Web Service技术,其中大部分涉及到了“属性”这个概念,而其英文术语则常常是Attribute、Property或者Field。很多人一概称之为“属性”,有的地方确实可以不加区分,但有的地方却是差之毫厘、谬以千里。我对于这些纷纷扰扰的技术和术语也很苦恼,但是我们至少可以通过UML中的这两个术语的解释找到一个可以参考的标准。无论如何,UML是面向对象技术的集大成者和事实上的标准。 UML1.4中的Attribute和Property 造成Attribute和Property理解混乱的罪魁祸首有一半是OMG自己,因为在UML1.4以前的规范中,Property并没有当作一个标准的术语出场,而是叫做Element Properties。其定义如下[1]: Many kinds of elements have detailed properties that do not have a visual notation. In addition, users can define new element properties using the tagged value mechanism. A string may be used to display properties attached to a model element. This includes properties represented by attributes in the metamodel as well as both predefined and user-defined tagged values. 许多模型元素含有详细的特性(properties),它们并没有可视化的符号。另外,用户可以使用标记值(tagged value)机制定义新的模型元素特性。一个字符串可以被用来显示附着在模型元素上面的特性。它包括在元模型中用来表示特性(properties)的属性(attribute)以及预定义和用户自定义的标记值。 从上面的定义可以看出,OMG的本意是将Property作为表示模型元素特性的统一术语。模型元素是UML所有建模元素的顶层父类和原子成分,Class也是一种模型元素。因此Property是用来修饰一部分模型元素的,而不仅仅是用来修饰Class的。另外一层含义是,Property包含了Attribure和tagged value,它的概念范围应该比Attribute要大。 再来看看Attribute在UML1.4规范中的定义[2]: An attribute is a named slot within a classifier that describes a range of values that instances of the classifier may hold. In the metamodel, an Attribute is a named piece of the declared state of a Classifier, particularly the range of values that Instances of the Classifier may hold. 一个属性(attribute)是类元(classifier)中的一个命名的槽(named slot),它用来描述此类元的实例可能拥有的取值范围。在元模型中,一个属性是一个类元的可命名的声明状态,尤其表示了这个类元的实例可能拥有的取值范围。 由此可知,Attribute是与Classifier相关联的术语,它比Property的影响范围要小。Class是Classifier的子类,因此Attribute也可以表示Class的属性。从上面的定义还可以看出,Attribute可以是Classifier的实例的命名的槽。对于Class来说,其实例就是Object,Object的槽就是对象的属性值槽。因此,Attribute是可以作为对象的属性的。而Property似乎没有这一层的含义。按MOF(元对象设施,OMG的另一个规范,后面会有详细解释)的模型层次划分,Attribute涉及的模型层从M2到M0,而Property似乎只是M2层的概念。 很客观的说,UML1.4中对于这两个术语并没有很清晰的定义,但是其区别还是显而易见的。Attribute应该是UML1.4中的宠儿,而Property连一个单独的术语都没有捞到。谁也没想到在UML2.0中风云突变,Attribute从类图中消失了,而Property堂而皇之入主中原。 UML2.0抛弃Attribute了么? 当我看到UML2.0的类图元模型的那一刹那,第一个感觉就是“Attribute哪儿去了?”下面是UML2.0中的Core::Basic包中的类图元模型[3]: 从图中可以清晰的看到,Class仅仅聚合了两个元素:Property和Operation。而Attribute却从类图元模型中消失了。 先看看此元模型中Property的定义[4]: A property is a typed element that represents an attribute of a class. 一个特性(property)是一个有类型的元素(typed element),它代表了一个类中的一个属性(Attribute)。 哇,这个定义是不是在搞笑?各位别急,别忘记了UML2.0中的类图元模型可不止一个,它的类图元模型是由三个分散的部分组成的。除了上面提到的Core::Basic::Class Diagram之外,还有Core::Constructs::Class Diagram和Class Diagram from Kernel Package。下面再来看看Core::Constructs::Class Diagram[5]: 可以看出这个图与上面的不同之处是加入了Classifier和Association,Class、Property和Operation三巨头还在。这个图对于Property的定义几乎可以解开我心中的疑惑了: A property is a structural feature of a classifier that characterizes instances of the classifier. Constructs::Property merges the definition of Basic::Property with Constructs::StructuralFeature. When a property is owned by a class it represents an attribute. In this case it relates an instance of the class to a value or set of values of the type of the attribute. When a property is owned by an association it represents a non-navigable end of the association. In this case the type of the property is the type of the end of the association. Property represents a declared state of one or more instances in terms of a named relationship to a value or values. When a property is an attribute of a classifier, the value or values are related to the instance of the classifier by being held in slots of the instance. When a property is an association end, the value or values are related to the instance or instances at the other end(s) of the association (see semantics of Association). 一个property是一个类元(classifier)的结构化特征,它用来刻画这个类元的实例。Constructs包中的Property(Constructs::Property)结合了Basic::Property和Constructs::StructuralFeature的定义。 当一个property被一个class拥有时它代表一个attribute。在这种情况下,它将一个class的实例联系到一个具体值或者一组值,这些值的类型符合attribute的类型。 当一个property被一个连接(association)拥有时它代表一个非导向的连接端。在这种情况下这个property的类型就是这个association的连接端的类型。 Property表达了一个或者一些实例的声明状态,它使用了一个命名的关系将实例连接到一个值或者一组值。当一个property是一个classifier中的attribute的时候,它通过将值储存在这个classifier的实例的槽(slot)中来给一个实例赋值。当一个property是一个关联端(association end)的时候,它的值被关联到association另一个关联端的实例。 从上面的定义中可以看出,Property同时代表了Attribute和Association end,如果它的owningAssociation不为空,则表明它属于一个Association,这时它代表了一个关联端;如果它的owningAssociation为空,则表明它不属于一个Association,这时它代表了类的一个Attribute。同时,Property继承了UML1.4中的定义,它可以用来表示标记值(Tagged Value)。 那么Attribute呢?UML2.0彻底抛弃它了么?不是的,它的定义依然存在[6]: A structural feature of a classifier that characterizes instances of the classifier. An attribute relates an instance of a classifier to a value or values through a named relationship. 一个类元的结构特征,它能够刻画这个类元的实例。一个Attribute通过一个命名的关系将一个类元的实例联系到一个或者一组具体值。 比起UML1.4中的定义,这个定义要简洁多了,Attribute这里仅仅指一个类元的结构特征,可以将类元的实例联系到一个或者一组具体值。而没有提到实例的槽(slot)等等。我猜想,这是因为UML2.0中已经把Attribute作为Property的一个子集了,所以关于实例的槽(slot)等等的具体赋值方法,都归结到Property的定义中解释了。 另外一点值得注意的是,Attribute的定义来自于术语表,而没有在元模型图中出现。而Property出现在元模型图中,并且都做了详细而具体的解释。这一点可以看出,UML强化Property,弱化Attribute的决心。 Attribute和Property的总结 这一节对Attribute和Property作一个小结,基于目前最新的UML2.0规范:
- 总体上来说,Attribute是Property的子集,Property会在适当的时机表现为Attribute;
- Property出现在类图的元模型中,代表了Class的所有结构化特征;Attribute没有出现在元模型中,它仅仅在Class的概念中存在,没有相应的语法了;
- Property有详细的定义和约束,而Attribute没有详细的定义,因此也不能用OCL写出其约束。
- Property和Attribute都是M2层的概念。在M1层,它们的实例是具体类的属性;在M0层,它们的实例的实例是具体对象的槽中存储的值。
上面多次提到了MOF的四层模型,这应该是属于MDA范畴中的概念,下面这一小节给出一个例子,希望能够说明Attribute和Property及其实例在不同的模型层中扮演的角色。 元模型图、模型图、对象图 MOF的四层模型分别是:元元模型层(M3)、元模型层(M2)、模型层(M1)、运行时(M0)。其中元元模型层包含了定义建模语言所需的元素;元模型层定义了一种建模语言的结构和语法;模型层定义了一个具体的系统的模型;运行时包含了一个模型的对象在运行时的状态等。 本文涉及到的有M2、M1和M0层,下面给出一个例子,首先是M2层,它可以定义一个建模语言的结构和语法,例如: 这是一个简要的元模型图,它表示Class由Property和Operation组成,这张图符合UML2.0的概念,但是我们也可以这样画: 这样一来,Class包含三种元素:Attribute、AssociationEnd和Operation,这样我们就创建了一个新的元模型,也可以说创建了一个小的新建模语言。虽然它不符合UML2.0规范。 M1层模型就是我们通常简称的“模型”,它是系统的标准化表示,一般用建模语言来表示一个软件系统,例如下面的汽车和人的系统: 其中Car类表示汽车的模型,它有两个属性price和type,另外还有一个关联端owner(表示车主),这些都是Property的实例。Person类也有两个属性age和name,还有一个关联端car。可以看出,M1层模型中的元素都是M2层模型元素的实例,例如: Car和Person是Class的实例;price、type、age、name以及car、owner都是Property的实例;run()和drive()都是Operation的实例。 所谓“建模”实际上就是利用M2层定义的元模型作为建模语言来定义M1层的模型。 再来看看M0层,汽车和人系统的运行时对象图如下: 因为不态熟悉对象图,所以其中可能有疏漏,不过其意义是一目了然的。其中具体的对象属性就是Property的实例的实例了。例如type=medium,medium是M1层模型中type的实例值,type是M2层中Property的实例值。 后记 总算将这一篇写完了,在群里面和阿飞仔细讨论了好久,真的是非常辛苦,但是我觉得弄清楚了Attribute和Property的区别是非常有意义的。它们所涉及的范围很广,可谓知十而闻一。这篇似乎不能够叫“程序员眼中的UML了”,因为涉及了好多MDA的知识,而且离代码很远。不过我尽量写得清楚通俗一点,文中出现的术语都作了解释,希望能够让大家看懂。 文中的术语翻译来自于《UML参考手册》[7],因为UML很多术语的翻译不统一,因此我用了这本很著名的UML书的译法。同时注明了英文原文。 参考文献 1. UML1.4-01-09-67文档 289页 2. UML1.4-01-09-67文档 80页 3. UML 2.0 Infrastructure Final Adopted Specifcation03-09-15文档109页 4. UML 2.0 Infrastructure Final Adopted Specifcation03-09-15文档111页 5. UML 2.0 Infrastructure Final Adopted Specifcation03-09-15文档123页 6. UML 2.0 Infrastructure Final Adopted Specifcation03-09-15文档17页 7. UML参考手册 |