OCL和MDA
閑聊:
我的BLOG又是一周沒有更新了,倒不是因為懶,而是上周的大部分時間花在審閱兩篇稿件上了。而尚未發表的稿件不能公開討論,所以BLOG上面就空空如也了。這幾天集中精力讀《Object Constraint Language, The: Getting Your Models Ready for MDA, Second Edition》這本書,頗有心得。作者Jos Warmer是OCL的創始人,他對于這門語言的把握是最專業的,而且行文流暢,讀原著如同讀漢語一樣,不由得大發感慨,“好書即是好老師”。全書一共十章,分為兩大部分,第一部分User Manual包括前五章,主要講述OCL的由來、概念、簡單的使用和實現方法,以及與MDA的關系等;第二部分Reference Manual內容要深一些,講述了OCL的一些高級使用方法。
這幾天奮起疾“書”,以一天一章的速度看完了前五章,腦中彷佛有豁然開朗之感,尤其對于OCL和MDA的關系有了新的認識。
OCL和MDA的初感想
要談OCL和MDA之間的關系,先要搞清楚它們各自的定義。OCL的定義上次已經說過了,再貼過來看看:UML圖(例如類圖)通常不夠精細,無法提供與規范有關的所有相關部分。這其中就缺少描述模型中關于對象的附加約束。這些約束常常用自然語言描述。而實踐表明,這樣做經常造成歧義。為了寫出無歧義的約束,已經開發出幾種所謂的“形式語言”。傳統上的形式語言,缺點是僅適合于有相當數學背景的人員,普通商務或系統建模者則難以使用。OCL即為填補這一空白而來。它是一種保留了易讀易寫特點的形式語言。它已在IBM的保險分部作為一種業務建模語言開發出來,根植于 Syntropy 方法。
而MDA的定義如下:MDA是OMG提出的一種新的軟件開發方法,它定義了基于模型的開發過程,以及自動將模型映射到實現的方法。它提供了一種使用模型來指導系統的理解,設計,構造,開發,操作,維護和修改的方法。
直觀的來說,MDA是OMG定義的一種軟件開發方法,為了標準化這種開發方法,OMG定義一組規范來支持MDA,其中最重要的有:MOF,UML,XMI,CWM。目前MOF,UML和XMI的最新版本都是2.0(CWM不知道,本身就不熟悉它)。在UML2.0的規范中,用了一個單獨的部分來專門定義OCL(OCL在UML的較早版本中已經定義,不過沒有作為單獨的部分來定義)。這說明,OCL和MDA的關系是:OCL是MDA眾多標準中的UML標準中的一個子標準。
但是OCL在MDA中的重要性如何呢?
模型成熟度(Modeling Maturity Levels,MML)
在書中我首次見到了MML的概念,當然不一定是本書作者提出的,只不過是我以前孤陋寡聞罷了。MML指出了模型在你的軟件開發過程中扮演了一個什么樣的角色?并且指出了為了提高軟件開發效率你應該采取什么樣的措施。
下圖畫出了MML的六層示范圖:

第零層:沒有標準:模型存在于開發者的頭腦中;
第一層:文本表達:用自然語言寫下想法;
第二層:文本和圖:用自然語言以及一些圖來表達想法;
第三層:模型和圖:用建模語言描述的圖來表達模型,用自然語言加以輔助描述;
第四層:精確的模型:用一致而連貫的文本/圖來精確的描述模型,它們都是沒有歧義的,可以直接映射到編程語言;
第五層:只有模型:第五層的模型是對于系統的一個完備的、一致的、詳細和精確的描述。它足以進行全部的代碼生成工作,生成的代碼不需要任何改動即可運行。總而言之一句話:“模型可運行”!
通過以上MML的描述我們可以了解,如果使用UML來描述模型,但是不使用OCL來描述模型中的約束,那么只能達到第三層。如果使用UML+OCL,那么模型就是精確的,MML可以達到第四層。如果模型可以達到MML5,那么是我睡著了。。。當然我們堅信MML5總有一天會達到,那時我們就可以像使用高級語言一樣使用建模語言,而像不理今天的匯編一樣不理明天的高級語言。也許有一種叫做MVM(Model Virtual Machine)的東西就像今天的JVM一樣流行。
OCL用在了MDA的哪些方面?
從上一節可知,OCL是MDA的必要條件,但遠遠不是充分條件。但不可否認的是,OCL被廣泛用于MDA的各個方面。下面的兩張圖可以說明一部分問題:


第一張圖是MDA的一個典型的開發流程,建立PIM,描述轉換定義,利用轉換工具將PIM轉換為PSM。第二張圖是OCL在MDA典型開發流程中的使用。其中三個方面使用了OCL:第一是model的創建使用了OCL來描述模型中的約束;第二是模型轉換的定義可以使用OCL來描述;第三是建模語言可以使用OCL來創建。
其中讓人迷惑的是第一和第三有什么區別呢?用OCL來約束模型和用OCL來創建建模語言有什么區別?區別在于它們所屬元層次的不同,也就是MOF中所描述的模型層次不同。這不是繞口令!其實我剛剛接觸MDA的時候也認為模型、元模型、元元模型好像繞口令一樣,但這些概念在接觸中慢慢清晰起來。用OCL來約束模型是處于M1層,其模型是指對系統的描述,例如對一個信用卡管理系統的UML模型。而用OCL來建立建模語言是處于M2層,這時OCL是用來描述UML的元模型中存在的約束,因為元模型等于模型的語言,也就是用OCL來創建建模語言(可能叫用OCL來定義建模語言中的約束更好)。下面是一個UML元模型中使用OCL的例子:
context Interface
inv: features->select(f |f.oclIsKindOf( Attribute ) )->isEmpty()
這個OCL表達式說明,接口Interface中不能有屬性存在。如果UML的元模型中缺少OCL的描述,那么此元模型就不是一個“精確”的元模型,那么UML也就不是一個精確的建模語言了。那么MDA就離我們而去了!
OCL,約束自己,約束父親
由上可知,雖然OCL號稱“對象”約束語言,其實它可以對MOF的模型層次中的任一層次進行約束,從而表達出精確的模型(四層模型中任一層的模型)。
OCL可以約束M2層的模型,例如UML的元模型,而OCL的元模型也處于M2層,那么OCL是否可以約束自己的元模型呢?答案是肯定的。

上圖是OCL的元模型簡化圖,其中也用OCL對一些地方進行了描述:
context LoopExpression
inv: source.oclIsKindOf( Collection )
inv: iteratorVariable.type= source.oclAsType(Collection).elementType
上面的約束表達了LoopExpression中source的類型必須是Collection,而迭代子iterator的類型必須是source這個Collection中的元素的類型。由此可見,OCL的元模型也需要OCL來約束,否則這個元模型就是不“精確”的,可以說,OCL在某種程度上自定義了自己。
從M0(對象),M1(模型)到M2(元模型)都可以用OCL來描述,那么M3層呢?定義UML和OCL元模型的元模型MOF,是否需要用OCL來約束。答案是肯定的! 隨便舉一個例子:
[1] The multiplicity of Association::memberEnd is limited to 2 rather than 2..* (i.e. n-ary Associations are not supported).
context Association inv: memberEnd->size() = 2
[2] The type of Operation::raisedException is limited to be Class rather than Type.
context Operation inv: raisedException.oclIsType(Class)
約束1說明Association的memberEnd的數量必須是2,也就是說Association只能有兩個memberEnd;約束2說明Operation拋出的異常類型必須是Class。以上摘自MOF2.0規范。這說明MOF作為OCL的定義者,父親,同時也被OCL這個兒子約束著。
后記
OCL是MDA中不可缺少的一環,MDA即使離開了UML還有可能使用其他的建模語言來執行,但是離開了約束各層模型的OCL恐怕就處處漏風了。OCL以后很可能會作為一個單獨的規范從UML中分離出來。因為它不僅僅是一個“對象”約束語言,更是一個MDA約束語言,滲透在MDA的各個方面。文中還提到了OCL可以定義模型轉換,但是由于模型轉換的規范QVT還沒有最后確定,所以這個部分只是試探,而不是唯一標準。而目前的OCL如果要定義轉換,還必須做一些擴充,所以這里沒有介紹。
OCL和MDA,目前我的理解也僅限于此,希望看完整本書后,能夠有進一步的理解。