<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zhaobin

    增強信息技術;感悟商業(yè)管理;探索商業(yè)與技術融合;豐富自我修養(yǎng);享受時尚生活;記錄心路歷程;使Blog作為自我改變之記錄與監(jiān)督的平臺。
    posts - 25, comments - 59, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    EMF(Eclipse Modeling Framework)是一個模型架構和代碼生成工具,它可以用來建構以結構化數(shù)據(jù)為基礎的工具或者應用。作為MDA和Eclipse的結合體,它發(fā)展迅速,IBM的大部分工具產(chǎn)品如RSA等都將建立在它的基礎之上。

    樣例

    我們將構建一個簡單的手機庫管工具,它只維護種類信息,并不存儲數(shù)量庫位等。通過該工具,我們可以添加,刪除,修改主機及配件;維護主機,配件的功能;并且可以通過拖放將主機和相關配件組成一種配置。

     建立模型

     EMF通過JET和JMERGE來實現(xiàn)支持MDA,它可以從annotated Java, UML, or XML Schema三種模型生成Eclipse plug-in代碼。我們將用Rational Rose建立UML模型來作為系統(tǒng)模型。


      圖1:簡單的手機庫管工具的UML模型表示

    將模型導入Eclipse中

    建立EMF工程,在Wizard中會提示選擇初始化的模型內容。從Rose中讀取類模型以后,將生成了一個工程,其中包含兩個文件:.ecore和.genmodel。

    Ecore文件代表我們的模型本身,你可以通過修改它來改變模型。比如改變屬性的類型,類之間的關系等。你也完全 可以通過手動的方式建立ecore文件來創(chuàng)建整個模型。我們可以看到,在ecore模型中,所有的類被轉換為EClass;聚合關系變成了一個 EClass包含其它EClass作為EReference,例如主機、配置、配件都作為庫存的EReference。在這里,我們需要修改 EReference的Containment屬性,缺省的值是false。Containment屬性是在持久化時的一個重要屬性,它表明存儲時數(shù)據(jù)的 包含關系,如果全部保留為fasle,將不會有任何信息被存儲到文件中,除了頂級節(jié)點:庫存。應該以誰創(chuàng)建,誰包含為原則。比如庫存可以創(chuàng)建主機、配件、 配置,那么這些庫存的EReference的Containment屬性都應該設為true;而配置并不負責創(chuàng)建主機和配件,只是從庫存中現(xiàn)有的主機和配 件拖放過來的,那么它下面的主機,配件EReference的Containment屬性都應該為false。

     以XMI存儲為例,修改后存儲的格式應該為:

    <?xml version="1.0" encoding="UTF-8"?>
    <mobiles:庫存 xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:mobiles="http:///mobiles.ecore">
    <配置 配件="http://@配件.0" 主機="http://@主機.0"/>
    <配件>
    <功能/>
    </配件>
    <主機>
    <功能/>
    </主機>
    </mobiles:庫存>

    Genmodel文件主要維護著一些與生成代碼相關的設置,比如說,某個屬性可不可以修改。大部分的屬性都不用修改,我們要決定的仍然是EReference的屬性:Children,Create Child,Notify。

    Notify是表明它應不應該將在這個包含節(jié)點中有關自身的改變通知給其它的相同節(jié)點。比如某個主機V3在庫存中 創(chuàng)建之后被拖到某個配置里,這樣在整個樹上就存在兩個V3:一個是V3本身,另一個是它的一個引用。如果將配置中主機的Notify屬性設為true后, 改變配置中引用的V3價格,它就會把這個改變通知給V3自身,實現(xiàn)同步。通常情況下應將所有的EReference的Notify設為true。

    按照下表做出設置:

    包含節(jié)點 EReference Children Create Child Notify
    庫存 主機
    配件
    配置 True True True
    主機 功能 True True True
    主機 配件 True False True
    配件 功能 True True True
    配置 主機
    配件 True False True

    生成代碼并運行

    用EMF generator(缺省的Eidtor)打開genmodel文件,原來的工程中會生成Model代碼,兩個新的工程Edit和Editor工程會被生 成, Edit工程包含了一些方便編輯Model的代碼,Eidtor工程中大都是UI部分的代碼,不在本文范圍之內。

    .mobiles文件生成后,將會用Mobiles Model Editor打開。現(xiàn)在就可以在庫存中添加主機配件等,并將其拖到某個配置中去。這里所謂的Mobiles在缺省情況下與你的Rose文件的名字相同,在 Editor工程的Plugin.xml的editor擴展中可以看到生成的后綴。



     Model Plug-in

    EMF是從作為MOF規(guī)范在Eclipse的一個實現(xiàn)開始的,隨后通過大量的運用在工具的實現(xiàn),EMF成為一個有效的MOF API的一個核心子集的Java實現(xiàn)。EMF中的元數(shù)據(jù)被稱為Ecore。


     灰色的類代表抽象類,所有的類都繼承自Eobject。EPackage包含關于模型類(EClass)和數(shù)據(jù)類型(EDataType)的信息。 EClass描述一個建模的類,并且指定屬性和參考以描述實例的數(shù)據(jù)。EAttribute描述簡單數(shù)據(jù),它由一個EDataType來指定。 EReference描述一個類之間的關聯(lián);它的類型是一個Eclass。EFactory包含創(chuàng)建模型元素的方法。更多的關于Ecore的描述請參考 Eclipse官方網(wǎng)站。
    包和工廠
    前面說過EPackage包含所有關于EClass和EDataType的信息,參看生成的代碼mobiles. MobilesPackage,可以看到Eclass的feature ID聲明:

    int 主機 = 0;
     int 配置 = 1;

    feature ID僅僅是對所有的類元素(不包含類型信息)的一個int類型的編號,有了它可以使你很快的區(qū)分出是哪個類的哪個屬性。例如在某個類的屬性值發(fā)生改變后, 它的監(jiān)聽者會收到一個通知,通知里就包含了改變了的屬性的feature ID,這時你就可以簡單的通過一個switch方法來實現(xiàn)分派。

    MobilesPackage中另外的一些是關于類型的,例如:

    EClass get主機();
     EAttribute get主機_Name();

    在某些情況下這些元數(shù)據(jù)是非常重要的,比如在決定某個屬性的編輯框類型的時候。當然你也可以直接調用某個類型的create方法來創(chuàng)建對象:

    適配器

    EMF最重要的一個特性就是它對Adapter的定義。在EMF中Adapter有兩個功能,第一個是類似于 Observer的功能,它可以監(jiān)聽目標對象的變化然后做出相應的反映;另一個是通過它可以使目標對象不用繼承某個接口或者父類來實現(xiàn)其特有的功能。這一 節(jié)我們會結合Model Plug_in的代碼來探討Adapter的這兩個功能。

    Observer

    通常的Observer模式需要至少兩個類,監(jiān)聽者和目標對象。EMF中,監(jiān)聽者稱為Adapter,目標對象稱 為Notifier。每個Notifier都擁有一個eAdapters列表,維護著所有監(jiān)聽者的類型,一旦Notifier發(fā)生變化,它會遍歷 eAdapters列表將變化通知給列表中的每一個Adapter。所以假如某個Adapter想要監(jiān)聽這個Notifier,只需要將自己添加到 Notifier的eAdapters中。

    EMF中所有的對象都直接或間接繼承自Eobject,如同java中所有的類都繼承自Object一樣。而Eobject類已經(jīng)實現(xiàn)了Notifier接口,所以所有的EMF的類都可以是Notifier。

    Adapter需要自己來實現(xiàn)AdapterImpl,需要實現(xiàn)的方法主要有兩 個,isAdapterForType和notifyChanged。IsAdapterForType是用來判斷這個Adapter能不能監(jiān)聽某個 Notifier,notifyChanged包含著一旦Notifier發(fā)生了變化這個Adapter所要做出的所有相應。假設我們需要一個 Adapter,它來監(jiān)聽主機的變化,一旦任何關于主機的增刪改操作產(chǎn)生就將改變記錄在本地文件中。

    Notification類是由Notifier發(fā)出來的,它包含著發(fā)出者getNotifier(),改變之前的舊值getOldValue()和改變后的新值getNewValue()。象如下示例這樣使用這個Adapter:

    主機 machine= MobilesFactory. EINSTANCE. create主機();
     主機Adapter adapter = new主機Adapter();
     machine.eAdatpters().add(adapter);
     machine.setName(“V3”);

    你要自己實例化Adapter,并且把它添加到Notifier的eAdaters里去。假如在其它的某個地方你 有同樣的需求,但你不確定“主機Adapter”是否已經(jīng)被添加到“主機”的eAdatpters里了,你就需要遍歷現(xiàn)有的adapter,來判斷是否已 被添加。然后決定創(chuàng)不創(chuàng)建新的“主機Adapter”。事實上EMF提供了AdapterFactory來簡化你的工作。可以參照生成的代碼 mobiles.util. MobilesAdapterFactory.java。它只是一個框架,用來根據(jù)Notifier的類型生成相應的Adatpter并將其注冊到 Notifier的eAdapters列表中去。它還借用了MobilesSwitch類的分派功能。

     MobilesSwitch只做了一件事情,那就是根據(jù)Notifier的類型調用不同的case*方法。例如,如果Notifier是“主機”,它會 去調用case主機()方法。MobilesAdapterFactory中則實現(xiàn)了case主機()方法,調用create主機Adapter()來創(chuàng) 建“主機Adapter”。

    繼續(xù)上面的例子,我們實現(xiàn)一個AdapterFactory:

    public class MobilesAdapterFactoryImpl extends MobilesAdapterFactory{
    public static MobilesAdapterFactoryImpl
    INSTANCE = new MobilesAdapterFactoryImpl ();
    public Adapter create主機Adapter() {
    return new主機Adapter();
    }
    }

    用的時候就很簡單:

    主機 machine= MobilesFactory. EINSTANCE. create主機();
    MobilesAdapterFactoryImpl.INSTANCE.adapt(machine, 主機Adapter.class);
    machine.setName(“V3”);

    factory會遍歷machine的eAdapters,如果沒有“主機Adapter”則創(chuàng)建一個添加進去,否則返回已有的。

    行為擴展
     我們把日志功能提取出來,成為一個類:

    public interface Logger{
    public void log();
    }

    其實我們希望的是“主機”也能有日志功能,可以在自己改變之后將變化記錄下來。以往我們要做的就是讓“主機”繼承 Logger,然后實現(xiàn)log()方法記錄下自己這種特定類型的信息。但有的時候通過繼承來擴展行為并不是那么舒服,比如繼承的關系是死的,你不能在你不 需要的時候去掉這些擴展行為。通過Adapter你可以隨心所欲的控制這些擴展行為。

    public class 主機Adapter extends AdapterImpl implements Logger
    {
    public void notifyChanged(Notification notification) {
    if (notification.getNotifier() instanceof 主機)
    log();
    }

    public boolean isAdapterForType(Object type) {
    return type == 主機.class;
    }
    public void log(){
    //log the name, band,year,changed property name and its old value and new value
    }
    }

    用的時候同上邊一樣:

    主機 machine= MobilesFactory. EINSTANCE. create主機();
    MobilesAdapterFactoryImpl.INSTANCE.adapt(machine, 主機Adapter.class);
    machine.setName(“V3”);

    這個時候任何“主機”的變化都會引起“主機Adapter”執(zhí)行擴展了的log()方法,這一點與AOP很像。

    Model Class

     我們現(xiàn)在把目光關注到Model Plug_in中最重要的部分。首先是Model的接口,例如接口“主機”,它的定義非常簡單,就是些屬性的get,set方法。get方法很簡單,而set方法則比較有趣:

    public void setName(String newName) {
    String oldName = name;
    name = newName;
    if (eNotificationRequired())
    eNotify(new ENotificationImpl(this,
    Notification.SET,
    MobilesPackage.主機__NAME,
    oldName, name));
    }

    它不僅僅將類變量賦予了新值,還在需要Notify的時候發(fā)出了一個Notification。如同上一節(jié)所講的,這個Notification將包含發(fā)出者,改變的方式,改變的屬性標識(feature ID)、舊值和新值。

     隨后是一些e開頭的方法,他們都是用作反射的。例如eGet,根據(jù)feature ID返回相應的屬性值;eSet,根據(jù)feature ID設置相應的屬性值;eUnset,根據(jù)feature ID設置相應的屬性值為缺省值;eIsSet,根據(jù)feature ID判斷相應的屬性是否被設置過;

    限于篇幅的關系,EMF中還有很多高級的功能沒有在本文中介紹,比如持久化,Command pattern等;Edit工程里更是包含了集萬千寵愛于一身的ItemProvider,它們都非常重要,希望以后有機會能與讀者共同探討



    趙斌原創(chuàng),保留一切權利,轉載請保留引用:m.tkk7.com/zhaobin,注明轉載除外,謝謝!】
    主站蜘蛛池模板: 成人免费视频试看120秒| 日本免费污片中国特一级| 好爽…又高潮了免费毛片| 亚洲综合色丁香麻豆| 国产成人精品免费视频大| 亚洲免费观看在线视频| 99久久99这里只有免费费精品| 久久精品国产精品亚洲艾草网| 三级网站免费观看| 久久亚洲AV午夜福利精品一区| 污视频在线观看免费| 亚洲精品影院久久久久久| 午夜宅男在线永久免费观看网| 久久乐国产综合亚洲精品| 国产免费拔擦拔擦8x| 国产精品成人免费观看| 亚洲国产精品VA在线看黑人| xxxxx免费视频| 久久人午夜亚洲精品无码区| 国产成人亚洲综合| 少妇无码一区二区三区免费| 中国亚洲呦女专区| 亚洲精品动漫人成3d在线| 国产午夜精品免费一区二区三区 | 青青青国产在线观看免费 | 国产亚洲一区区二区在线| 无码AV片在线观看免费| tom影院亚洲国产一区二区| 亚洲AV无码一区二区三区国产| 国产免费拔擦拔擦8X高清在线人 | 一级**爱片免费视频| 久久久久久亚洲Av无码精品专口| 免费人成在线视频| 国产免费播放一区二区| 中文字幕亚洲综合小综合在线| 亚洲午夜精品久久久久久浪潮| 国产乱子精品免费视观看片| 免费人成又黄又爽的视频在线电影| 久久久亚洲精品国产| 国产高清免费在线| 99re在线免费视频|