您的位置:首页 > 其它

EMF学习笔记1——模型实体类

2010-11-02 20:15 162 查看
EMF是基于两种元模型来构建的,分别是Ecore和Genmodel。





Ecore:主要用于定义模型结构的相关信息,并对外提供了一个根对象(犹如XML文件的根节点)用来代表要显示的模型,该对象的子节点为package(包),package的子节点为class(类),class的子节点为attribute(类的属性字段),这样整个树形结构就代表了所要表示的EMF模型结构。

Genmodel:主要包含有关代码生成的相关信息(如:文件生成路径及文件名),和一些控制参数用来控制代码怎样生成。



EMF采用模型驱动开发方法,在无需编码的情况下,我们可以基于模型使用EMF为我们生成以下几样东西。

1,与模型相对应的EMF实体类。

2,基于实体类的各种ItemProvider模型适配器类,通过该适配器类可以很好的将EMF模型绑定到Jface组件中去,稍后具体介绍。

3,editor-plugin项目,可理解为基于EMF应用的一个插件项目。

4,测试bundle。





这里3和4不做介绍,主要讲解1,2。然后自定义一个Jface组件,将EMF模型应用与该组件之上。



在开始之前,我们需要了解以下几个名词的含义,也是文中多处提到的几个词:

1实体类:就像Hibernate ORM为我们生成的实体类一样,EMF也会为我们生成这样的实体类,并且这些实体类含有更高级的特性(如:类属性状态发生变化时,实体类具有通知功能)

2适配器类:EMF的模型结构可能非常复杂(如可能含有多个实体类,并且类结构各不相同),这样当视图组件直接使用这些实体类的时候就变得非常困难(要判断出是哪一个实体类,针对该实体类怎样显示视图等等..),因此EMF针对这些实体类生成了一些适配器类,通过实现指定的接口,让适配器类来设计实体类的显示,而视图只需要选择合适的适配类便可。

3适配器工厂:上面讲到视图通过适配器类避免了与实体类的直接交互,然而视图又是如何得到合适的适配器类的呢?那便是通过适配器工厂类。



模型定义如下:



从模型定义来看Library便是Ecore所对外提供的用来表示模型的根对象。

首先来看EMF为我们生成的模型实体类(假设这些实体类分布在org.emf.demo这个bundle之中)

EMF会为我们生成3个package,分别是:

org.emf.demo.library:包含实体类的接口;用于创建实体类的工厂(libraryFactory);访问模型元数据的实用类(LibraryPackage)

org.emf.demo.library.impl:实体类接口的实现类;实体类工厂的实现类(LibraryFactryImpl);LibraryPackage的实现类(LibraryPackageImpl)

org.emf.demo.library.util:针对该模型的适配器工厂类(LibraryAdapterFactory)

注:libraryFactory和LibraryPackage都是单例模式的,可通过其成员变量eINSTANCE来得到对象的实例。





在EMF中,所有的实体类接口全部继承EObject,换个角度,同Java领域的Object对象一样,EObject是EMF中所有类的基类。在实体类的定义中,我们强调过,除了具有一般JavaBean的特性之外,EMF实体类具有更高级的特性,因此其代码实现也较普通的javaBean更加复杂。

在EMF所生成的实体类的set方法中,除了要对成员变量进行赋值外,还要对其适配器类进行变更通知操作。以Book实体类的setPages方法为例:

public Writer getWriter() {
 if (Writer != null && Writer.eIsProxy()) {
  InternalEObject oldWriter = (InternalEObject)Writer;
  Writer = (Writer)eResolveProxy(oldWriter);
  if (Writer != oldWriter) {
   if (eNotificationRequired())
    eNotify(new ENotificationImpl(this, Notification.RESOLVE, WebpagePackage.BOOK__Writer, oldWriter, Writer));
  }
 }
 return Writer;
}


当Writer和Book两个实体类分别存储与不同的资源文件中时,EMF是采用延迟加载模式来加载对象的,因此这里的Writer对象可能只是Writer的一个代理类,而不是真正的对象引用,所以在getWriter()方法里,首先要判断其是不是代理类(eIsProxy()方法),如果是则调用eResoleProxy()方法来加载目标对象,然后判断目标对象与代理对象是否相同(引用同一个对象),如果不同则Book的Writer属性状态便发生了变化,要对其适配器类进行通知。



双向引用(two-way reference):

同单向引用相比,get方法没有变化,set方法的实现不同。以Book对象的setWriter()方法为例:

LibraryFactory factory=LibraryFactory.eINSTANCE;//得到创建实体类的工厂类
Book book=factory.createBook();//创建Book对象
Writer writer=factory.createWriter();//创建Writer对象
writer.setName("zhangsan");
book.setTitle("emf demo");
book.setPage(123);
book.setWriter(writer);//只是在book端执行了set操作

List<Book> books=writer.getBooks();//在writer端依然能够遍历到book
for(Book b:books){
 System.out.println(b.getTitle());
}


虽然我们只是在book端执行了setWriter方法,而没有在writer端执行添加book的方法,但是在writer端依然能够遍历到Book对象。

聚合引用:

所谓聚合引用,就是一个对象是另一个对象的容器;比如上面的Library和Book,Library便是Book的容器。

在EMF中,容器和它所包含的对象存储在同一资源文件中,因此在加载的时候不需要使用代理机制。

在聚合引用中,每个对象只能有一个容器,因此在将一个对象加入到某个容器之前,要将该对象从现在的容器中移除出去。为了实现该功能,EObjectImpl类中设计了一个成员变量eContainer用来表示实体类对象的容器,这样我们就可以通过book.eContainer()方法来得到Library对象。



注:EMF所生成的变量或方法都会含有@generated标注,当执行regenerate操作时EMF只会覆盖含有@generated标注的方法,而自己手工添加的方法不会被覆盖。

下一篇将会讲解EMF所生成的适配器类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: