程序员眼中的UML(4)
--类图释疑之一,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规范:
l 总体上来说,Attribute是Property的子集,Property会在适当的时机表现为Attribute;
l Property出现在类图的元模型中,代表了Class的所有结构化特征;Attribute没有出现在元模型中,它仅仅在Class的概念中存在,没有相应的语法了;
l Property有详细的定义和约束,而Attribute没有详细的定义,因此也不能用OCL写出其约束。
l 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参考手册