Eclipse Modeling Framework (EMF),簡(jiǎn)單的說(shuō),就是Eclipse提供的一套建??蚣?,可以用EMF建立自己的UML模型,設(shè)計(jì)模型的XML格式或編寫模型的java代碼。EMF提供了一套方便的機(jī)制,實(shí)現(xiàn)了功能的相互轉(zhuǎn)換,大大提高了效率,下面是其具體功能介紹:
一、統(tǒng)一java、UML、XML
為了幫助理解EMF,我們可以舉一個(gè)例子。假設(shè)老板要你寫需要寫一個(gè)程序,來(lái)管理供應(yīng)商的采購(gòu)清單,采購(gòu)清單需要維護(hù)三大項(xiàng):付款方(bill to)、運(yùn)送地址(ship to)和購(gòu)買貨物集合(集合中包含名字name、數(shù)量quantity、價(jià)格price)。你回答說(shuō):沒(méi)問(wèn)題。然后就開始設(shè)計(jì)采購(gòu)系統(tǒng)的java接口:
1 public interface PurchaseOrder 2 { 3 String getShipTo(); 4 void setShipTo(String value); 5 String getBillTo(); 6 void setBillTo(String value); 7 List getItems(); // List of Item 8 }
9 public interface Item10 {11 String getProductName();12 void setProductName(String value);13 int getQuantity();14 void setQuantity(int value);15 float getPrice();16 void setPrice(float value);17 }
然后就準(zhǔn)備開始實(shí)現(xiàn)自己的接口,忽然老板問(wèn)了一句,“你不要先建立自己的模型嗎”,對(duì)于大多數(shù)從來(lái)不建模的java程序員,你認(rèn)為代碼就是模型,用那些形式化建模元素建立模型除了能在文檔中增加篇幅外,沒(méi)有任何好處,但即使如此,你仍然要聽(tīng)老板的話,所以你建立了如圖1所示的UML模型。
圖1 采購(gòu)系統(tǒng)的UML模型
這里,你可以要求老板走開,然后編碼實(shí)現(xiàn)了,但首先你還得保存模型,這里我們你想到了用XML文件保存,自詡聰明之時(shí),寫好了如下的XML schema文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 3 xmlns:po="http://www.example.com/SimplePO" 4 targetNamespace="http://www.example.com/SimplePO"> 5 <xsd:complexType name="PurchaseOrder"> 6 <xsd:sequence> 7 <xsd:element name="shipTo" type="xsd:string"/> 8 <xsd:element name="billTo" type="xsd:string"/> 9 <xsd:element name="items" type="po:Item"10 minOccurs="0" maxOccurs="unbounded"/>11 </xsd:sequence>12 </xsd:complexType>13 <xsd:complexType name="Item">14 <xsd:sequence>15 <xsd:element name="productName" type="xsd:string"/>16 <xsd:element name="quantity" type="xsd:int"/>17 <xsd:element name="price" type="xsd:float"/>18 </xsd:sequence>19 </xsd:complexType>20 </xsd:schema>
在下一步工作之前,你突然意識(shí)到現(xiàn)在已經(jīng)有三種系統(tǒng)表示:Java interfaces、UML模型和 XML Schema,你開始思考,同一個(gè)系統(tǒng)設(shè)計(jì)了三種模型(暫且認(rèn)為XML和接口也是模型),進(jìn)行了大量重復(fù)的工作,有沒(méi)有一種方法,只設(shè)計(jì)其中的一種模型,然后實(shí)現(xiàn)三者之間的相互轉(zhuǎn)換?
此時(shí),EMF出現(xiàn)了,EMF是一個(gè)建??蚣埽軌?qū)崿F(xiàn)java代碼的生成,即它統(tǒng)一了三種重要的技術(shù):Java, XML 和 UML。如圖2所示。
圖2 EMF 統(tǒng)一了UML、XML、java
假設(shè)你要操作一個(gè)XML文檔,如果你是XML schema大牛,你可以從設(shè)計(jì)schema開始,然后通過(guò)EMF得到UML模型,再通過(guò)EMF得到j(luò)ava代碼,當(dāng)然如果你不是,可以從設(shè)計(jì)UML模型開始,一樣可以完成上述功能。
二、建模 vs 編程
這里有的人可能會(huì)問(wèn):難道EMF只是一個(gè)描述模型和生成其它東西的框架嗎?回答是的,但不全面,EMF的功能遠(yuǎn)不止此,它能有效地為編程服務(wù),這也是一個(gè)經(jīng)典問(wèn)題的答案:“我是應(yīng)該先建模還是直接寫代碼?”,EMF的回答是兩者都可以,因此在EMF看來(lái),兩者是等價(jià)的。用英語(yǔ)回答就是:"To model or to program, that is not the question."
三、定義模型
上面我們用三種形式描述了我們的概念模型,那么這三者有沒(méi)有共同的模型概念,方便它們之間的轉(zhuǎn)換呢(模型轉(zhuǎn)換的知識(shí)在此暫時(shí)省略)?我們?cè)倩仡櫹虑懊娴娜N模型:
可以看到這三者都用到了一種較高層的定義來(lái)分別表達(dá)UML、XML、java。因此,要實(shí)現(xiàn)EMF和模型之間的轉(zhuǎn)換,我們需要這種能夠描述EMF模型的模型,我們稱為元模型。
1、Ecore (Meta)模型
能夠描述EMF的模型稱為Ecore元模型(位于MOF的M2層,關(guān)于MOF可以參考http://en.wikipedia.org/wiki/Meta-Object_Facility),它本身也是EMF模型,因此Ecore是它自己的元模型。如果再深入一點(diǎn),Ecore的元模型又是什么呢?回答仍然是Ecore,因?yàn)樗梢悦枋鲎陨?。Ecore只是OMG的MOF在Eclipse下的一種實(shí)現(xiàn),可能還有其它元模型形式(可以參考http://wenku.baidu.com/view/d28de6717fd5360cba1adb28.html第二段),這里就不詳細(xì)介紹了。圖3給出了一個(gè)簡(jiǎn)化的Ecore元模型,說(shuō)它是簡(jiǎn)化的,是因?yàn)樗皇荅core元模型的子集,而且為了方便,將某些公共類省略,如ENamedElement類(這個(gè)類定義了類中屬性的名字)。
圖3 簡(jiǎn)化的Ecore元模型
從圖2中可以看到,我們需要四種Ecore類來(lái)描述我們的模型,它們是:
我們還可以觀察到,Ecore元模型這么類似于UML中的類圖,這不足為怪,因?yàn)閁ML本來(lái)就是一種統(tǒng)一的建模語(yǔ)言(名符其實(shí)),倒是有另一點(diǎn)可能不明白?即然Ecore也是UML,為什么不用UML作為UML的元模型呢?答案很簡(jiǎn)單,因?yàn)镋core只是UML的子集,沒(méi)有必要用到除類圖以外的其它UML元素。
有了Ecore元模型,我們就可以用我們的例子實(shí)例化Ecore元模型,圖4是采購(gòu)系統(tǒng)的Ecore實(shí)例(如果對(duì)此不理解,可以參考http://www.cnblogs.com/riky/archive/2007/04/07/704298.html)。
圖4 采購(gòu)系統(tǒng)的Ecore實(shí)例
2、XMI序列格式
有了Ecore元模型后,可能有人會(huì)問(wèn):“Ecore的序列化格式(Serialized form)是什么呢?”是Java code、XML Schema 和 UML diagram中的一種嗎?實(shí)際上,Ecore的規(guī)范序列化格式是XMI(XML Metadata Interchange),為什么會(huì)出現(xiàn)另外一種XMI格式,而不用前面介紹的三種格式呢?首先,Java code、XML Schema 和 UML diagram都增加了Ecore本身并不具有的信息,已經(jīng)改變了Ecore;其次,Java code、XML Schema 和 UML diagram中沒(méi)有一種能夠適用于任何場(chǎng)合,即沒(méi)有一種是通用的,而XMI正好滿足這兩點(diǎn)。我們的采購(gòu)系統(tǒng)Ecore實(shí)例可以用下面的XMI序列表示:
<?xml version="1.0" encoding="UTF-8"?><ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="po" nsURI="http://www.example.com/SimplePO" nsPrefix="po"> <eClassifiers xsi:type="ecore:EClass" name="PurchaseOrder"> <eStructuralFeatures xsi:type="ecore:EAttribute" name="shipTo" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> <eStructuralFeatures xsi:type="ecore:EAttribute" name="billTo" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> <eStructuralFeatures xsi:type="ecore:EReference" name="items" upperBound="-1" eType="#//Item" containment="true"/> </eClassifiers> <eClassifiers xsi:type="ecore:EClass" name="Item"> <eStructuralFeatures xsi:type="ecore:EAttribute" name="productName" eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EString"/> <eStructuralFeatures xsi:type="ecore:EAttribute" name="quantity" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> <eStructuralFeatures xsi:type="ecore:EAttribute" name="price" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat"/> </eClassifiers></ecore:EPackage>
當(dāng)我們聽(tīng)到別人要導(dǎo)出EMF模型時(shí),實(shí)際上就是導(dǎo)出EMF的XMI。
3、java注釋
我們已經(jīng)知道EMF能夠?qū)ava接口自動(dòng)生成UML的屬性和方法,但是否所有的接口都能生成呢?或者什么樣的接口才能生成呢?首先,EMF并不會(huì)盲目地把所有的java接口自動(dòng)生成UML的屬性和方法,其次,只有符合特定規(guī)范才能通過(guò)EMF生成(EMF使用的是JavaBeans簡(jiǎn)單屬性祖先命名模式的子集,具體規(guī)范可參考http://java.sun.com/products/javabeans/docs/spec.html)。根據(jù)此規(guī)范,需要用@model標(biāo)明哪些接口需要用EMF生成模型。例如前面給的PurchaseOrder接口就需要用下面的格式來(lái)生成UML:
/** * @model */public interface PurchaseOrder{ /** * @model */ String getShipTo(); /** * @model */ String getBillTo(); /** * @model type="Item" containment="true" */ List getItems();}
4、Ecore "Big Picture"
我們先來(lái)回顧前面的知識(shí):
其實(shí),通過(guò)XML schema定義模型有一個(gè)優(yōu)勢(shì):給定schema后,可以序列化成持久模型的實(shí)例。因?yàn)閄ML schema不僅僅定義了模型,還指定了模型實(shí)例的持久格式。問(wèn)題出來(lái)了:是否還有其它的持久模型格式呢?回答是肯定的,例如relational database (RDB) Schema等。Ecore的"big picture"如圖5所示。
圖5 Ecore及其源格式
四、生成代碼
EMF最主要的功能莫過(guò)于其自動(dòng)代碼生成能力了,能夠極大提高工作效率。假設(shè)我們已經(jīng)有了上面的模型,生成轉(zhuǎn)換成Java代碼呢?你只要新建EMF項(xiàng)目,它即自動(dòng)加載了生成器。那么,EMF生成是的是什么樣的代碼呢?
首先,Ecore類(即EClass)相當(dāng)于java的兩個(gè)實(shí)體:接口及其實(shí)現(xiàn)類。例如對(duì)于EClass PurchaseOrder相當(dāng)于java的:
public interface PurchaseOrder ...public class PurchaseOrderImpl extends ... implements PurchaseOrder {
是這種設(shè)計(jì)方式,是因?yàn)槲覀冋J(rèn)為這是類模型API(如文檔對(duì)象模型DOM)的最好模式。
其次,每個(gè)生成的接口都直接或間接擴(kuò)展了基接口EObject,如:
public interface PurchaseOrder extends EObject {
EObject是java.lang.Object的EMF等價(jià)物,即所有模型對(duì)象的基礎(chǔ)。擴(kuò)展的EObject包含下面三種行為:
然后,EObject還是另一個(gè)接口的擴(kuò)展:
public interface EObject extends Notifier {
最后,根據(jù)類型及用戶設(shè)定的屬性生成代碼。例如:
public String getShipTo(){ return shipTo;}
對(duì)于相應(yīng)的set()會(huì)有點(diǎn)不同,它會(huì)對(duì)其它可能對(duì)此屬性狀態(tài)改變的觀察者發(fā)出通知,如:
public void setShipTo(String newShipTo){ String oldShipTo = shipTo; shipTo = newShipTo; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, POPackage.PURCHASE_ORDER__SHIP_TO, oldShipTo, shipTo));}
注意到當(dāng)沒(méi)有觀察者時(shí),為了避免調(diào)用eNotify()花費(fèi)的高昂代價(jià),EMF會(huì)添加一個(gè)eNotificationRequired()守衛(wèi)條件。
五、總結(jié)
本篇由淺入深的介紹了EMF的相關(guān)知識(shí),由于篇幅原因,不可能將全部的EMF知識(shí)都寫在這里,感興趣的讀者可以通過(guò)參考書籍了解其它內(nèi)容。
六、參考資料
1. Steinberg, D., Budinsky, F., Paternostro, M., Merks, E.: Eclipse Modeling Framework, 2nd Edition. Pearson Education (2008)
聯(lián)系客服