zoukankan      html  css  js  c++  java
  • umf(转)

    深入浅出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 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 Item 10 { 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 }
    复制代码

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

    图1 采购系统的UML模型

      这里,你可以要求老板走开,然后编码实现了,但首先你还得保存模型,这里我们你想到了用XML文件保存,自诩聪明之时,写好了如下的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>
    复制代码

      在下一步工作之前,你突然意识到现在已经有三种系统表示: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序列表示:

    复制代码
    <?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>
    复制代码

       当我们听到别人要导出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:

    复制代码
    /**
     * @model
     */
    public interface PurchaseOrder
    {
     /**
     * @model
     */
      String getShipTo();
     /**
     * @model
     */
      String getBillTo();
     /**
     * @model type="Item" containment="true"
     */
      List getItems();
    }
    复制代码

    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的:

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

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

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

    public interface PurchaseOrder extends EObject {

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

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

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

    public interface EObject extends Notifier {

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

    public String getShipTo()
    {
      return shipTo;
    }

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

    复制代码
    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));
    }
    复制代码

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

    五、总结

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

    六、参考资料

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

  • 相关阅读:
    Lambda表达式、依赖倒置
    ASP.NET vNext 概述
    Uname
    RHEL4 i386下安装rdesktop【原创】
    Taxonomy of class loader problems encountered when using Jakarta Commons Logging(转)
    How to decompile class file in Java and Eclipse
    先有的资源,能看的速度看,不能看的,抽时间看。说不定那天就真的打不开了(转)
    Google App Engine 学习和实践
    【VBA研究】VBA通过HTTP协议实现邮件轨迹跟踪查询
    js正則表達式语法
  • 原文地址:https://www.cnblogs.com/yelongsan/p/5445903.html
Copyright © 2011-2022 走看看