EMF 自学笔记 4

大致浏览过八进制的blog后,开始啃帮助文档,希望不会磕到牙齿^_^

 

The Eclipse Modeling Framework (EMF) Overview —— EMF概述

EMF is a Java framework and code generation facility for building tools and other applications based on a structured model. <EMF是一个Java框架和代码生成工具,基于结构化的模型创建应用程序>

后面开始吹嘘EMF,先吹它可以把你建好的面向对象的模型迅速的转变成很好很强大的代码,接着又吹它的使用门槛很低,甚至都不需要图形化建模工具blablabla.

EMF使用XMI(XML Metadata Interchange) 作为模型定义的标准形式,同时它提供以下手段将你的模型转变为标准形式:

  • 直接创建XMI文件并编辑(我觉得这纯粹是用来凑数的)
  • 将使用Rational Rose 等建模工具创建的模型导出为XMI文件
  • 使用带注解的Java Interfaces(前面就是用这用方式的)
  • Use XML Schema to describe the form of a serialization of the model(不大理解,以后再看)

EMF Relation to OMG MOF —— EMF与MOF的关系

与之前笔记一致,EMF是MOF API核心子集的高效Java实现,EMF中类似MOF的核心元模型称为Ecore.

 

Generating a Java Implementation —— 生成一个Java实现 内容摘要

(a)最基本的Java类的实现:

接口定义:public interface Book extends EObject {...//提供所有属性的getter setter方法和相关类的引用}

EObject在EMF中等效于 java.lang.Object, 它是所有EMF类的基础。 EObject和它的实现类EObjectImpl提供了EMF通知机制和持久化框架

实现类部分代码:public class BookImpl extends EObjectImpl implements Book {
    public void setPages(int newPages) {
        int oldPages = pages;
        pages = newPages;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, ..., oldPages, pages));
    }
} eNotify会发送值改变通知(Notification.SET)给所有的监听器。

(b)One-way references 单向引用

EMF持久化框架使用懒加载机制,所以一个对象指针有是可能只是指向一个代理对象,而不是实际的引用对象,在使用对象指针前要小心。在EMF框架生成的get方法中是这样确认 xxx.eIsProxy() 这样转化 xxx= (XXXX)eResolveProxy((InternalEObject)xxx) 的。要注意的是eResolveProxy()方法可能会解析失败,这时函数返回的是原来的代理对象,这就意味着get方法是可能返回代理对象的,我们使用get方法时要考虑这个问题。

(C)Two-way references 双向引用

Book类的setAuthor(Writer newAuthor)方法的处理流程:

  1. 判断newAuthor与原来的author是否是同一对象(没用equals方法)。如果是同一对象,简单的发送一个TOUCH通知,函数退出。
  2. 如果原author不是null,需要把这本书从原author的著作列表中删除(因为author引用是单一的,即一本书只能有一个作者),可调用((InternalEObject)author).eInverseRemove(this, LibraryPackage.WRITER__BOOKS, Writer.class, msgs);
  3. 如果newAuthor不是null,需要把这本书加到newAuthor的著作列表中,可调用((InternalEObject)newAuthor).eInverseAdd(this, LibraryPackage.WRITER__BOOKS, Writer.class, msgs);
  4. 为该book设置newAuthor,调用basicSetAuthor(newAuthor, msgs); 函数结束。basicSetAuthor()方法与(b)中的setAuthor()方法类似。
  5. 由于2-4总共涉及到3次不同的通知,为了能让这些相关的通知共同发送而引入了NotificationChain类,通过调用其dispatch()方法发送所有通知。到此函数结束。

调试代码时,发现eInverseRemove调用了WriterImpl类的eInverseRemove方法,该方法重写(override)了基类的方法如下:

switch (featureID) {
    case LibraryPackage.WRITER__BOOKS:
    return ((InternalEList<?>)getBooks()).basicRemove(otherEnd, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);

WRITER__BOOKS是自动生成的int常量,用作Writer模型的一个feature id, 表明了Writer模型对Book模型的引用关系。作为eInverseRemove方法的参数,它表明了该反向删除是处理从Writer类到Book类的引用关系。
同样的,eInverseAdd调用了WriterImpl类的eInverseAdd方法。

如果简单的理解的话,WriterImpl类的eInverseRemove和eInverseAdd方法就是负责给WriterImpl类增删引用关系关联的对象的。比如eInverseRemove就是简单的从该Writer的著作列表中删除掉第一个参数传入的那本书(如果Writer有其它引用关系,比如Medal,那就通过case LibraryPackage.WRITER__MEDALS:这条分支处理)。只不过这些方法不是给我们调的,而是给框架回调的。

(d)Multiplicity-many references 多重引用

在EMF中,多重引用(0..*)使用集合来操作,接口中只生成getter方法。

public interface Writer extends EObject {
    EList getBooks();
} EList对应java.util.List. 实际上,EList是java.util.List的子类,仅仅增加了两个move API,其用法与标准Java List类似。

EMF提供了20种不同的EList实现(它们都基于EcoreEList)来处理各种各样的多重引用关系,例如EObjectEList用来处理不使用代理的单向多重引用,EObjectResolvingEList(继承自EObjectEList)处理单向多重引用,EObjectWithInverseEList(继承自EObjectEList)用来处理不使用代理的双向多重引用,EObjectWithInverseResolvingEList(继承自EObjectWithInverseEList)用来处理双向多重引用。

Writer类使用EObjectWithInverseResolvingEList,getBooks()方法中这样创建:

books = new EObjectWithInverseResolvingEList(Book.class, this,
                    LibraryPackage.WRITER__BOOKS, LibraryPackage.BOOK__AUTHOR);

调试给作者添加一本书这种业务功能时发现像aWriter.getBooks().add(aBook)这样调用add方法,最终会调用到BookImpl类的eInverseAdd方法,方法体如下:

switch (featureID) {
    case LibraryPackage.BOOK__AUTHOR:
    if (author != null)
        msgs = ((InternalEObject)author).eInverseRemove(this, LibraryPackage.WRITER__BOOKS, Writer.class, msgs);
    return basicSetAuthor((Writer)otherEnd, msgs);
}
return super.eInverseAdd(otherEnd, featureID, msgs);
该方法还是可以简单理解为负责给BookImpl类增加引用关系关联的对象。由于一本书只能有一个作者,所以如果此书已设置过作者,就必须先把原作者编写了这本书这条关系给去掉。BookImpl类的eInverseAdd方法的实现与上述逻辑完全一致。

(e)Containment References 组合引用

组合引用意味着组合对象与容器在同一resource中(因为容器要管理组合对象的生命周期),所以不存在代理方案(proxy resolution)。单向的组合引用使用EObjectContainmentEList, 双向的使用EObjectContainmentWithInverseEList.

每个组合对象只能有一个容器,处理组合对象时(比如为组合对象指定新容器时)要注意这点。

EObjectImpl基类维护了一个eContainer变量用来记录每个实例的Container,可以这样使用:

EObject container = book.eContainer();
if (container instanceof Library)
    library = (Library)container;

当然了,如果定义的是双向的组合引用,EMF会自动生成安全的get方法为组合对象获取容器实例。

(f)Enumeration Attributes 枚举属性

没啥好说的

(g)Factories and packages 工厂和包裹

工厂接口提供了其实现类的一个实例eINSTANCE,若干createXXX API和一个获取package的API。使用工厂类创建对象代码如下:

LibraryFactory.eINSTANCE.createWriter();

Package接口提供了对模型元数据(metadata)的快捷访问API. 比如 EClass getBook() 函数将返回代表Book模型的Ecore元数据;而 EAttribute getBook_Title() 函数将返回代表Book模型Title属性的Ecore元数据。

(h)Generating classes with super classes 子类的生成

单一继承的实现很简单,接口继承父类接口,实现类继承父类实现类。

public interface SchoolBook extends Book

public class SchoolBookImpl extends BookImpl implements SchoolBook

实现多重继承的策略是实现类继承指明为<<extend>> stereotype 的类,其余的转化为属性

public interface SchoolBook extends Book, Asset

public class SchoolBookImpl extends BookImpl implements SchoolBook {
    public float getValue() {... }
    public void setValue(float newValue) {... }
} 其中的value就是Asset类的属性。

(i)Customizing the generated implementation classes

重新生成代码的覆盖逻辑:

  • 如果目标函数(指生成器计划生成的函数)不存在,则生成。
  • 如果目标函数已存在,且有@generated注解,则覆盖。
  • 如果目标函数已存在,且没有@generated注解,则去寻找函数名为“目标函数名+Gen” 的函数。
  • 如果“目标函数名+Gen”的函数存在且有@generated注解,则覆盖该函数。
  • 其余情况(“目标函数名+Gen”的函数不存在或没有@generated注解),则忽略。

技巧:如果我们要定制setAuthor方法,加上打印信息,可以直接修改该方法然后去掉@generated注解,但这样的话setAuthor方法就不再归入EMF框架管理,如果今后模型关系发生更改(比如author关联关系也变为0..*,即一本书可以有多个autor)而我们又忘了修改该方法,就会出错。可以这样解决:将setAuthor方法更名为setAuthorGen并加上@generated注解,定制setAuthor方法时调用setAuthorGen和加上打印信息,就解决了这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值