深入浅出Eclipse Modeling Framework (EMF)

  Eclipse Modeling Framework (EMF),简单的说,就是Eclipse提供的一套建模框架,可以用EMF建立自己的UML模型,设计模型的XML格式或编写模型的java代码。EMF提供了一套方便的机制,实现了功能的相互转换,大大提高了效率,下面是其具体功能介绍:

一、统一java、UML、XML

  为了帮助理解EMF,我们可以举一个例子。假设老板要你写需要写一个程序,来管理供应商的采购清单,采购清单需要维护三大项:付款方(bill to)、运送地址(ship to)和购买货物集合(集合中包含名字name、数量quantity、价格price)。你回答说:没问题。然后就开始设计采购系统的java接口:

  1. 1 public interface PurchaseOrder
  2. 2 {
  3. 3   String getShipTo();
  4. 4   void setShipTo(String value);
  5. 5   String getBillTo();
  6. 6   void setBillTo(String value);
  7. 7   List getItems(); // List of Item
  8. 8 }
  9. 9 public interface Item
  10. 10 {
  11. 11   String getProductName();
  12. 12   void setProductName(String value);
  13. 13   int getQuantity();
  14. 14   void setQuantity(int value);
  15. 15   float getPrice();
  16. 16   void setPrice(float value);
  17. 17 }

  然后就准备开始实现自己的接口,忽然老板问了一句,“你不要先建立自己的模型吗”,对于大多数从来不建模的java程序员,你认为代码就是模型,用那些形式化建模元素建立模型除了能在文档中增加篇幅外,没有任何好处,但即使如此,你仍然要听老板的话,所以你建立了如图1所示的UML模型。

图1 采购系统的UML模型

  这里,你可以要求老板走开,然后编码实现了,但首先你还得保存模型,这里我们你想到了用XML文件保存,自诩聪明之时,写好了如下的XML schema文件:

  1. 1 <?xml version="1.0" encoding="UTF-8"?>
  2. 2 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  3. 3        xmlns:po="http://www.example.com/SimplePO"
  4. 4        targetNamespace="http://www.example.com/SimplePO">
  5. 5   <xsd:complexType name="PurchaseOrder">
  6. 6     <xsd:sequence>
  7. 7       <xsd:element name="shipTo" type="xsd:string"/>
  8. 8       <xsd:element name="billTo" type="xsd:string"/>
  9. 9       <xsd:element name="items" type="po:Item"
  10. 10               minOccurs="0" maxOccurs="unbounded"/>
  11. 11     </xsd:sequence>
  12. 12   </xsd:complexType>
  13. 13   <xsd:complexType name="Item">
  14. 14     <xsd:sequence>
  15. 15       <xsd:element name="productName" type="xsd:string"/>
  16. 16       <xsd:element name="quantity" type="xsd:int"/>
  17. 17       <xsd:element name="price" type="xsd:float"/>
  18. 18     </xsd:sequence>
  19. 19   </xsd:complexType>
  20. 20 </xsd:schema>

  在下一步工作之前,你突然意识到现在已经有三种系统表示:Java interfaces、UML模型和 XML Schema,你开始思考,同一个系统设计了三种模型(暂且认为XML和接口也是模型),进行了大量重复的工作,有没有一种方法,只设计其中的一种模型,然后实现三者之间的相互转换?

  此时,EMF出现了,EMF是一个建模框架,能够实现java代码的生成,即它统一了三种重要的技术:Java, XML 和 UML。如图2所示。

图2 EMF 统一了UML、XML、java

  假设你要操作一个XML文档,如果你是XML schema大牛,你可以从设计schema开始,然后通过EMF得到UML模型,再通过EMF得到java代码,当然如果你不是,可以从设计UML模型开始,一样可以完成上述功能。

二、建模 vs 编程

  这里有的人可能会问:难道EMF只是一个描述模型和生成其它东西的框架吗?回答是的,但不全面,EMF的功能远不止此,它能有效地为编程服务,这也是一个经典问题的答案:“我是应该先建模还是直接写代码?”,EMF的回答是两者都可以,因此在EMF看来,两者是等价的。用英语回答就是:"To model or to program, that is not the question."

三、定义模型

  上面我们用三种形式描述了我们的概念模型,那么这三者有没有共同的模型概念,方便它们之间的转换呢(模型转换的知识在此暂时省略)?我们再回顾下前面的三种模型:

  • PurchaseOrder and Item 在UML和java中是类,但在XML schema中是复杂类型定义;
  • shipTo, billTo, productName, quantity 和 price在UML中是属性,在java中是get()/set()方法对,在XML schema中是内嵌的元素类型;
  • items在UML是类的关联或引用,在java中是get()方法,在XML schema中是另一种复杂类型的内嵌元素类型。

  可以看到这三者都用到了一种较高层的定义来分别表达UML、XML、java。因此,要实现EMF和模型之间的转换,我们需要这种能够描述EMF模型的模型,我们称为元模型。

1、Ecore (Meta)模型

  能够描述EMF的模型称为Ecore元模型(位于MOF的M2层,关于MOF可以参考http://en.wikipedia.org/wiki/Meta-Object_Facility),它本身也是EMF模型,因此Ecore是它自己的元模型。如果再深入一点,Ecore的元模型又是什么呢?回答仍然是Ecore,因为它可以描述自身。Ecore只是OMG的MOF在Eclipse下的一种实现,可能还有其它元模型形式(可以参考http://wenku.baidu.com/view/d28de6717fd5360cba1adb28.html第二段),这里就不详细介绍了。图3给出了一个简化的Ecore元模型,说它是简化的,是因为它只是Ecore元模型的子集,而且为了方便,将某些公共类省略,如ENamedElement类(这个类定义了类中属性的名字)。

图3 简化的Ecore元模型

  从图2中可以看到,我们需要四种Ecore类来描述我们的模型,它们是:

  • EClass 用于表示模型中的类,它有一个name,0个或多个attributes,0个或多个references。
  • EAttribute 用于表示模型中的attribute,它有一个name和一个type。
  • EReference 用于表示两个类之间的关联,它有一个name,一个布尔值表示它是否是containment,还有一个引用类型(其它类)。
  • EDataType 用于表示attribute的类型,它可以是基本类型,例如int 、 float 或对象类型 java.util.Date等.

  我们还可以观察到,Ecore元模型这么类似于UML中的类图,这不足为怪,因为UML本来就是一种统一的建模语言(名符其实),倒是有另一点可能不明白?即然Ecore也是UML,为什么不用UML作为UML的元模型呢?答案很简单,因为Ecore只是UML的子集,没有必要用到除类图以外的其它UML元素。

  有了Ecore元模型,我们就可以用我们的例子实例化Ecore元模型,图4是采购系统的Ecore实例(如果对此不理解,可以参考http://www.cnblogs.com/riky/archive/2007/04/07/704298.html)。

图4 采购系统的Ecore实例

2、XMI序列格式

  有了Ecore元模型后,可能有人会问:“Ecore的序列化格式(Serialized form)是什么呢?”是Java code、XML Schema 和 UML diagram中的一种吗?实际上,Ecore的规范序列化格式是XMI(XML Metadata Interchange),为什么会出现另外一种XMI格式,而不用前面介绍的三种格式呢?首先,Java code、XML Schema 和 UML diagram都增加了Ecore本身并不具有的信息,已经改变了Ecore;其次,Java code、XML Schema 和 UML diagram中没有一种能够适用于任何场合,即没有一种是通用的,而XMI正好满足这两点。我们的采购系统Ecore实例可以用下面的XMI序列表示:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="po"
  5.          nsURI="http://www.example.com/SimplePO" nsPrefix="po">
  6.   <eClassifiers xsi:type="ecore:EClass" name="PurchaseOrder">
  7.     <eStructuralFeatures xsi:type="ecore:EAttribute" name="shipTo"
  8.                 eType="ecore:EDataType
  9.                 http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  10.     <eStructuralFeatures xsi:type="ecore:EAttribute" name="billTo"
  11.                 eType="ecore:EDataType
  12.                 http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  13.     <eStructuralFeatures xsi:type="ecore:EReference" name="items"
  14.                 upperBound="-1" eType="#//Item" containment="true"/>
  15.   </eClassifiers>
  16.   <eClassifiers xsi:type="ecore:EClass" name="Item">
  17.     <eStructuralFeatures xsi:type="ecore:EAttribute"
  18.                 name="productName" eType="ecore:EDataType
                    http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  19.     <eStructuralFeatures xsi:type="ecore:EAttribute" name="quantity"
  20.                 eType="ecore:EDataType
  21.                 http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
  22.     <eStructuralFeatures xsi:type="ecore:EAttribute" name="price"
  23.                 eType="ecore:EDataType
  24.                 http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
  25.   </eClassifiers>
  26. </ecore:EPackage>

   当我们听到别人要导出EMF模型时,实际上就是导出EMF的XMI。

 3、java注释

  我们已经知道EMF能够将java接口自动生成UML的属性和方法,但是否所有的接口都能生成呢?或者什么样的接口才能生成呢?首先,EMF并不会盲目地把所有的java接口自动生成UML的属性和方法,其次,只有符合特定规范才能通过EMF生成(EMF使用的是JavaBeans简单属性祖先命名模式的子集,具体规范可参考http://java.sun.com/products/javabeans/docs/spec.html)。根据此规范,需要用@model标明哪些接口需要用EMF生成模型。例如前面给的PurchaseOrder接口就需要用下面的格式来生成UML:

  1. /**
  2. * @model
  3. */
  4. public interface PurchaseOrder
  5. {
  6. /**
  7. * @model
  8. */
  9.   String getShipTo();
  10. /**
  11. * @model
  12. */
  13.   String getBillTo();
  14. /**
  15. * @model type="Item" containment="true"
  16. */
  17.   List getItems();
  18. }

4、Ecore "Big Picture"

  我们先来回顾前面的知识:

  • Ecore和它的XMI序列化格式是EMF的核心;
  • EMF模型至少可以通过三种形式得到(UML、XML schema、Java 接口);
  • 通过Ecore模型可以生成Java接口及其它形式的模型;

  其实,通过XML schema定义模型有一个优势:给定schema后,可以序列化成持久模型的实例。因为XML schema不仅仅定义了模型,还指定了模型实例的持久格式。问题出来了:是否还有其它的持久模型格式呢?回答是肯定的,例如relational database (RDB) Schema等。Ecore的"big picture"如图5所示。

图5 Ecore及其源格式

四、生成代码

  EMF最主要的功能莫过于其自动代码生成能力了,能够极大提高工作效率。假设我们已经有了上面的模型,生成转换成Java代码呢?你只要新建EMF项目,它即自动加载了生成器。那么,EMF生成是的是什么样的代码呢?

  首先,Ecore类(即EClass)相当于java的两个实体:接口及其实现类。例如对于EClass PurchaseOrder相当于java的:

  1. public interface PurchaseOrder ...
  2. public class PurchaseOrderImpl extends ... implements PurchaseOrder {

  是这种设计方式,是因为我们认为这是类模型API(如文档对象模型DOM)的最好模式。

  其次,每个生成的接口都直接或间接扩展了基接口EObject,如:

  1. public interface PurchaseOrder extends EObject {

  EObject是java.lang.Object的EMF等价物,即所有模型对象的基础。扩展的EObject包含下面三种行为:

  • eClass()返回对象的元对象(是一个EClass)。
  • eContainer() and eResource() 分别返回对象的包含对象及其资源。
  • eGet(), eSet(), eIsSet(), and eUnset() 提供了访问交互对象的API。

  然后,EObject还是另一个接口的扩展:

  1. public interface EObject extends Notifier {

  最后,根据类型及用户设定的属性生成代码。例如:

  1. public String getShipTo()
  2. {
  3.   return shipTo;
  4. }

  对于相应的set()会有点不同,它会对其它可能对此属性状态改变的观察者发出通知,如:

  1. public void setShipTo(String newShipTo)
  2. {
  3.   String oldShipTo = shipTo;
  4.   shipTo = newShipTo;
  5.   if (eNotificationRequired())
  6.     eNotify(new ENotificationImpl(this,
  7.                       Notification.SET,
  8.                       POPackage.PURCHASE_ORDER__SHIP_TO,
  9.                       oldShipTo, shipTo));
  10. }

  注意到当没有观察者时,为了避免调用eNotify()花费的高昂代价,EMF会添加一个eNotificationRequired()守卫条件。

五、总结

  本篇由浅入深的介绍了EMF的相关知识,由于篇幅原因,不可能将全部的EMF知识都写在这里,感兴趣的读者可以通过参考书籍了解其它内容。

六、参考资料

  1. Steinberg, D., Budinsky, F., Paternostro, M., Merks, E.: Eclipse Modeling Framework, 2nd Edition. Pearson Education (2008)

umf(转)的更多相关文章

  1. RDA UMF进程 & UMF_IR.C 遥控处理

    SIS架构图: SW Structure APP Event Flow :消息分发流程 UMF进程: int umf_main(int argc, char* argv[]) { umf_Init() ...

  2. Android Studio开发RecyclerView遇到的各种问题以及解决(一)

    以前一直在用ListView,,,最近才看RecyclerView发现好强大.RecyclerView前提是Android版本在5.0以上,本人以前用的是eclipse只支持到4.4.索性就安装一个A ...

  3. Oracle 内置sql函数大全

    F.1字符函数--返回字符值 这些函数全都接收的是字符族类型的参数(CHR除外)并且返回字符值.除了特别说明的之外,这些函数大部分返回VARCHAR2类型的数值.字符函数的返回类型所受的限制和基本数据 ...

  4. C# if中连续几个条件判断

    C# if中连续几个条件判断 1.if (条件表达式1 && 条件表达式2) 当条件表达式1为true时 using System; using System.Collections. ...

  5. 浏览器渲染引擎,提高css渲染速度。

    一.渲染引擎渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上.默认情况下渲染引擎可以显示HTML,XML文档以及图片. 通过插件(浏览器扩展)它可以显示其它类型文档. 二.各种渲染引擎我 ...

  6. Oracle学习笔记十三 触发器

    简介 触发器是当特定事件出现时自动执行的存储过程,特定事件可以是执行更新的DML语句和DDL语句,触发器不能被显式调用.   触发器的功能: 1.自动生成数据 2.自定义复杂的安全权限 3.提供审计和 ...

  7. OpenCv图像裁剪指点区域_roi

    两种方式Range和ROI #include <opencv2/opencv.hpp> using namespace std; using namespace cv; void test ...

  8. java基础学习总结-接口

    原文链接:http://www.cnblogs.com/xdp-gacl/p/3651121.html 一.接口的概念 JAVA是只支持单继承的,但现实之中存在多重继承这种现象,如"金丝猴是 ...

  9. 10分钟学会前端调试利器——FireBug

    概述 FireBug是一个用于网站前端开发的工具,它是FireFox浏览器的一个扩展插件.它可以用于调试JavaScript.查看DOM.分析CSS.监控网络流量以及进行Ajax交互等.它提供了几乎前 ...

随机推荐

  1. 排序算法总结(四)快速排序【QUICK SORT】

    感觉自己这几篇都是主要参考的Wikipedia上的,快排就更加是了....wiki上的快排挺清晰并且容易理解的,需要注意的地方我也添加上了注释,大家可以直接看代码.需要注意的是,wikipedia上快 ...

  2. YOLO: Real-Time Object Detection 安装和测试

    1.下载darknet git clone https://github.com/pjreddie/darknet.git 2.修改make GPU= CUDNN= OPENCV= DEBUG= 3. ...

  3. php开发api接口

    做过 API 的人应该了解,其实开发 API 比开发 WEB 更简洁,但可能逻辑更复杂,因为 API 其实就是数据输出,不用呈现页面,所以也就不存在 MVC(API 只有 M 和 C),那么我们来探讨 ...

  4. Linux下安装php加速器xcache

    一.环境说明 php安装目录:/usr/local/php php.ini配置文件路径:/usr/local/php/etc/php.ini Nginx安装目录:/usr/local/nginx Ng ...

  5. SpringMVC处理静态资源

    若将DispatcheServlet请求映射设置为/,则SpringMvc将捕获WEB容器的所有请求,包括静态资源的请求,SpringMvc会将它们当成一个普通的请求处理,那么将会出现因找不到对应的处 ...

  6. PostMessager来对子父窗体进行跨域

    一.为什么需要使用postMessage这个跨域技术 对于一个普通的页面而言,如果页面中的数据量太多时,会导致某个页面的数据量太多 二显得特别的臃肿,所以通常是使用iframe的方式来加载子页面,但是 ...

  7. Yii里增删改查的操作方法

    一.AR $model=New user();//user是数据库中的一张表,有id,name,pwd字段 1.增加: <1. $model->name='张三': $model-> ...

  8. Angular SEO方案

    1.如果是java web项目,可以直接使用AngularSEO Filter. 官网地址 :http://www.angularseo.net/#about <filter> <f ...

  9. 每天一个 Linux 命令(7):mv命令

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 1.命令格式: mv [选项] 源文件或目 ...

  10. 【cl】Json学习

    http://www.cnblogs.com/java-pan/archive/2012/04/07/2436507.html