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

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

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

    hello world

    隨筆 - 2, 文章 - 63, 評論 - 0, 引用 - 0
    數據加載中……

    【轉】Netbeans Platform: Lookup! Lookup!

    Netbeans Platform的Lookup類給我們帶來了什么呢?注入依賴和解耦!Lookup的基本用法常常是:

    Foo foo = someLookup.lookup(Foo.class)

    使用Lookup來查找一個Foo類的實例。你可以將Lookup想成是一個Map,鍵是類,值是實例。

    Netbeans中Lookup用途有:

    1. 表現一個對象的能力。IS-A關系轉變為HAS-A關系。

    想 想傳統的一種解耦方式:將其他模塊創建的對象cast到特定的類型。Netbeans,不這么做,Netbeans做法是讓其他模塊創建的對象實現 Lookup.Provider接口(這個接口只有一個方法:public Lookup getLookup()),然后通過這個Lookup獲得你需要協同工作的對象。然后你的代碼詢問這個對象是否擁有特定接口的實例:

    Your code  <--   interact with --> Some object -- implements --> Lookup.Provider

                                                             |__ has a Lookup Object -- maintain

                                                                                                            |__ Object 1

                                                                                                            |__ Object 2

                                                                                                            |__ Object 3 ...

    這 樣,通過Lookup, Some object 將 IS-A 關系(Some object實現Object1接口,Object2接口,Object3接口)轉化為HAS-A關系(Some object的lookup對象擁有Object1, Object2, Object3).

    這種轉化具有重要的意義!方便!快捷!動態 (運行時無法改變實現的接口和類型)!彈性(運行時一個對象的能力是可能變化的,但是類型是不能變化的)!例如如果你想保存一個對象,你不必問其是否實現 Saveable接口,你只需要問其是否擁有一個SaveCookie實例(SaveCookie有一個save方法)。

    2. 依賴注射和解耦

    一個模塊能夠定義多個接口讓其他模塊實現這些接口,這個模塊可以使用Lookup.getDefault()方法獲得全局Lookup,然后根據全局Lookup查找其接口的所有實現。

    3. 動態服務發現

    模塊能夠非常簡單的將代表全局服務或偽單例的對象通過默認的Lookup進行注射。

    單 例模式的的目的是讓一個對象只擁有一個實例。實現這種模式又很多方法,例如最簡單的是創建一個工廠方法,然后將構造器定義為私有的,然后維護一個實例,對 所有的調用(工廠方法)都返回這個實例。單例模式在Netbeans中也有廣泛的應用。通常全局服務沒有必要有多個實例,例如在整個應用程序的主窗口中我 們只需要一個狀態顯式欄實例,來顯式狀態。例如Netbeans的Windows系統API,你不用直接使用它,這個模塊 org.netbeans.core.windows將StatusDisplayer實現注射進來,放在默認的Lookup中,你僅僅使用 StatusDisplayer.getDefault().setStatusText("something").就可以設置狀態信息了。

    Lookup.Result 和 Lookup.Template

     

    什么樣的對象需要擁有自己的Lookup呢?

    在Netbeans中的一些基本API類中又很多都有getLookup()方法,他們都實現了Lookup.Provider接口。Netbeans中有三個著名的例子:

    1. Project. Project API . Project實際就是一個將一個目錄和一個Lookup結合在一起,再加點東西的一個對象。Project API 定義了能在一個Project實例的Lookup中出現的(可選的)類。不同的模塊實現了Project,提供自己的實現。其他API定義一些其他的類。 例如Java Project API定義了一個ClassPathProvider的接口。這個接口能在Java源代碼Project的Lookup中被找到,而其他普通的 Project沒必要有這個接口。整個Project類定義如下:

    public interface Project extends Lookup.Provider {

    // 維護一個文件對象,代表項目目錄
    FileObject getProjectDirectory();

    // 維護一個Lookup對象
    Lookup getLookup();
    }

    可以從Project的Lookup中請求多個接口。例如ProjectInformation對象能夠提供Project名稱等基本信息。

    2. TopComponent . 頂層組件是Netbeans的窗口系統管理的一個GUI面板。繼承于TopComponent的類可以通過TopComponent.getLookup()方法來操作面板中的選擇等事務。

    3. Node. 節點就是通常說得樹-節點類型的對象,代表底層的數據模型。例如項目和文件窗口中的文件樹就是節點樹。org.openide.nodes.Node就有getLookup()方法。

    說了Netbeans中著名的三種具有Lookup對象的類,到底什么樣的對象需要Lookup對象呢??

    答案是,需要暴露某些能力的對象。這些對象可以通過Lookup對象向外界表明其具備某些能力,從而讓其他代碼能夠使用這些對象的能力。舉個例子,如果你想保存一個文件對象,那么這個文件對象肯定有保存的能力。傳統方式怎么做呢:

    public void actionPerformed (ActionEvent e) {
    Object o = something.getSelection();

    // 你會檢查其是否實現Saveable接口
    if (o instanceof Saveable && ((Saveable) o).canSave()) {
    ((Saveable) o).save();
    }
    }

    可 惜的是這種方法太不強大了。Java對象無法輕易更改他們的類型。因為情況總是在變化的。Java文件包括源文件和編譯文件,有些事情你無法在只有源文件 沒有編譯文件的情況下做,例如執行。并不是所有Java源文件都有對應的編譯文件的。因此Lookup的出現能夠很好的解決這種問題。Java文件的 Lookup內容是可以隨時變化。當Java源文件被編譯后,可以向Java文件的Lookup內容添加一個編譯文件對象,如果Java文件被編譯了,那 么Lookup內容中就保存一個編譯文件對象,如果編譯文件被刪除了,這個編譯對象也從Lookup內容中刪除了。

    public void actionPerformed (ActionEvent e) {
    Lookup lkp = Utilities.actionsGlobalContext();
    SaveCookie save = lkp.lookup (SaveCookie.class);
    if (save != null) {
    save.save();
    }
    }

    事 實上,Netbeans中一個正在被編輯的文件的保存過程,就是代表這個文件的節點Node的Lookup中出現了一個SaveCookie對象。這個代 碼并不需要知道SaveCookie.save()方法的具體細節,只需要知道SaveCookie對象在Lookup中,就可以保存。

    Lookup是一種通訊機制

    上 面說得Project就是一個例子,Netbeans中有一個概念叫服務提供者接口(Service Provider Interface, SPI ). 不同的模塊通過在默認的Lookup中安裝ProjectFactory實例,來插入不同的項目類型project type.你可以在Netbeans的項目向導中發現你可以創建不同類型的項目。Netbeans包含多個項目接口的實現。

    Lookup和代理

    ProxyLookup允許將兩個Lookup融合。

    Lookup和選擇

    那我們如何在程序中使用Lookup呢?

    基本上說,我們無需自己編寫Lookup(當然如果需要的話,你可以編寫)。

    NetBeans 的 Lookup 可以說是無處不在,它也是 NetBeans 中最基本的模塊。在執行的時候,NetBeans 將Lookup分為系統服務池的Lookup和具有焦點窗口的對象池的Lookup。我們可以從以下地方獲得Lookup:TopComponentNodeUtilities.actionsGlobalContext()、和 Lookups四個地方。

    我 們通過Utilities.actionsGlobalContext()來獲得對象池的Lookup, 這里Netbeans已經幫我們整合過Lookup對象了.Utilities.actionsGlobalContext()將返回一個Lookup對 象,這個對象是活動的(具有焦點)的頂層組件的Lookup的代理Lookup,如果頂層組件是Explorer視圖的話,將代理被選擇了的節點的 Lookup對象們。

    我們通過Lookup.getDefault()方式獲得系統服務池的Lookup.

    Netbeans平臺為我們準備好了幾種使用方式:

    1. 通過Lookups. 如果你需要包含固定數目對象的Lookup,你可以使用Lookups.fixed(Object... objectsToLookup) (注意:... 代表可變參數數量),也可以使用Lookups.singleton(Object objectToLookup)返回一個只包含一個對象的Lookup.

    2. AbstractLookup和InstanceContent. 如果你希望你的Lookup可以動態的包含對象(數目可變),那么你可以使用AbstractLookup和InstanceContent相結合的方 式。注意AbstractLookup并不是抽象類。具體的用法這里有個很好的例子,Fox的Lookup講解

    在 這個例子中,有一個業務對象FoxObject, 有兩個頂層組件:Consumer頂層組件和Producer頂層組件。Producer頂層組件中包含兩個狀態按鈕 (ToggleButton):FoxButton和DonButton。Consumer頂層組件有一個List表單。

    效果是:如果你 按下Producer頂層組件窗口中的其中一個Button,就會創建一個FoxObject對象,其名字根據按鈕的名字命名,例如按下 DonButton將創建一個名字為Don的FoxObject. 如果程序的焦點在Producer頂層組件上(藍色背景意味焦點在其上,灰色背景意味焦點不在其上)的話,Consumer頂層組件的List表單將出現 這個名字為Don的FoxObject, 當你再次按下DonButton時,按鈕的狀態改變,名字為Don的FoxObject被刪除,List表單中相應的對象也消失了。如果你將程序焦點換到 Consumer頂層組件的時候,List表單中的所有對象都消失了,重新將焦點換到Producer頂層組件上時,List表單中的對象重新出現了。

    這是怎么實現的呢?我們看一下:

    1. 我們在Producer頂層組件中維護一個InstanceContent對象,兩個FoxObject對象。在Producer頂層組件構造的時候,我們初始化Lookup:

    private void initLookup(){

            // 創建InstanceContent,然后構建一個AbstractLookup,然后將這個Lookup和Producer頂層組件關聯
            m_InstancePool=new InstanceContent(); 
            this.associateLookup(new AbstractLookup(m_InstancePool)); 
        }

    在ToggleButton狀態變化方法中,我們根據Button的狀態,決定InstanceContent的內容(名為Don的FoxObject對象的添加和刪除)

    private void m_PutDonItemStateChanged(java.awt.event.ItemEvent evt) {                                         
            if(evt.getStateChange()==ItemEvent.SELECTED){
                if(m_Don==null){
                    m_Don=FoxObject.createInstance("don", "Don, Chen");
                }
                m_InstancePool.add(m_Don);
            }else if(evt.getStateChange()==ItemEvent.DESELECTED){
                if(m_Don!=null){
                    m_InstancePool.remove(m_Don);
                }
            }
        }          

    2. 我們讓Consumer頂層組件實現LookupLisenter, 因為他要根據FoxObject對象的狀態來顯式List表單。他維護一個JList表單以及一個Lookup.Result結果。

    final class ConsumerTopComponent extends TopComponent implements LookupListener {...

    當Consumer頂層組件被打開和關閉時:

    public void componentOpened() {
            clearList();

            // 初始化LookupQuery
            initLookupQuery();
            FoxService oService=(FoxService) Lookup.getDefault().lookup(FoxService.class);
            if(oService !=null ){
                oService.saySomething();
            }
        }
        public void componentClosed() {

            // 關閉LookupQuery
            uninitLookupQuery();
            clearList();
        }

    我 們看一下,在Consumer頂層組件窗口被打開時,我們根據FoxObject類制作一個模版,然后通過 Utilities.actionsGlobalContext()查找到所有FoxObject的實例,以Lookup.Result方式展現。找到這 些FoxObject實例后,對代表他們的Lookup.Result添加監聽器,就是Consumer頂層組件自己。然后更新結果列表。

    private void initLookupQuery(){
            Lookup.Template oFoxTemplate=new Lookup.Template(FoxObject.class);
            m_LookupResult=Utilities.actionsGlobalContext().lookup(oFoxTemplate);
            m_LookupResult.addLookupListener(this);
            refreshResultList();
        }
        private void uninitLookupQuery(){
            if(m_LookupResult!=null){
                m_LookupResult.removeLookupListener(this);
                m_LookupResult=null;
            }
        }

    實現Lookup監聽器的方法:

    public void resultChanged(LookupEvent ev){
            refreshResultList();
        }

    一旦Lookup變化了,resultChanged方法就被調用,執行refreshResultList方法。這個方法獲得Lookup.Result中的所有實例,如果有實例的話,重新根據這些實例繪制Consumer頂層組件的List表單。

    private void refreshResultList(){
            Collection<FoxObject> cList=m_LookupResult.allInstances();
            if(!cList.isEmpty()){
                this.m_FoxObjectList.setListData(new Vector<FoxObject>(cList));
                this.m_FoxObjectList.revalidate();
                this.m_FoxObjectList.repaint();
            }else{
                clearList();
            }
        }

    整個演示就完成了。這里我們特別要注意幾點:

    1. FoxObject是業務對象,它僅僅關注自己的業務和信息,例如名字,ID等,對其他的事情一概不知。

    2. Producer頂層組件需要和一個Lookup關聯,這個Lookup是AbstractLookup和InstanceContent共同完成的,以便Lookup內的對象數目可以動態改變(通過ToggleButton的狀態):

    ProducerTopComponent --> AbstractLookup --> InstanceContent     --> FoxObject Class

                                                         |                       |__ Add/Remove --> Fox FoxObject <--> Button1

                                                         |                       |__ Add/Remove --> Don FoxObject <--> Button2

                                                         |

                                                         |    關鍵:Netbeans通過Utilities.actionsGlobalContext將

                                                         |    Producer頂層組件和Consumer頂層組件解耦,相互通過Lookup溝通

    ConsumerTopComponent --> Utilities.actionsGlobalContext().lookup(FoxObject.class)

                           |______  監聽 -->      |__ Lookup.Result

                                             |______  更新 -->     JList (根據Lookup.Result的變化)

    3. 結構圖

                   <--------------                                 FoxObject                       --------------->

                   |                                                              |                                                   |

                   |        <-----   Lookup (Utilitis, AbstractLookup, InstanceConent)  ------>       |

                   |         |                                                                                                |       |

         ConsumerTopComponent                                XXX                  ProducerTopComponent


    轉自http://alarnan.spaces.live.com/blog/cns!819cbc613de169ef!141.entry

    posted on 2009-09-17 16:36 聽風 閱讀(1464) 評論(0)  編輯  收藏 所屬分類: JAVA

    主站蜘蛛池模板: 在线观看日本免费a∨视频| 成人电影在线免费观看| 成人免费看吃奶视频网站| 亚洲综合久久一本伊伊区| 人成午夜免费视频在线观看| 亚洲最新黄色网址| 免费H网站在线观看的| 亚洲18在线天美| 免费看a级黄色片| 免费无码专区毛片高潮喷水 | 国产免费无码AV片在线观看不卡| 亚洲精品亚洲人成在线观看| 野花香高清视频在线观看免费 | yy一级毛片免费视频| 亚洲中文久久精品无码| 国产精品成人免费一区二区| 久久久久se色偷偷亚洲精品av| 四虎永久在线精品免费网址| 久久精品国产亚洲AV天海翼| 国产亚洲精品国看不卡| 最近免费中文字幕大全免费| 亚洲综合av一区二区三区| 亚洲国产高清在线一区二区三区| 久久免费精品视频| 亚洲精品一二三区| 亚洲国产成人VA在线观看| 久久伊人免费视频| 亚洲一区二区三区丝袜| 久久久久久久亚洲精品| 国产精品免费观看| 黄色免费网站在线看| 久久久久久亚洲AV无码专区| 免费无遮挡无码视频网站| 毛片基地看看成人免费| 亚洲三级高清免费| 国产亚洲精品AA片在线观看不加载| 0588影视手机免费看片| 免费无码av片在线观看 | 亚洲一区二区三区四区视频| 亚洲国产精品日韩| 青娱乐免费在线视频|