程序員眼中的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的實例。
所謂“建?!睂嶋H上就是利用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參考手冊