在基礎篇中已經通過例子初步說明了如何基於CNF制作一個簡單的資源管理器但很多開發人員並不理解樹上的結點是如何得到的這就涉及到CNF的模型在詳述CNF的模型之前需要先對Tree所使用的模型進行描述
對於早期習慣C/S開發的程序員來說對於SWT中的Tree並不陌生可以通過相應的TreeItem來創建子結點但是這並不是一種好的設計和使用方式它大大的增加了模型與UI之間的耦合度所以在Swing中使用了TreeNode來描述樹模型而Eclipse則通過JFace提供了ITreeContentProvider接口來描述樹模型這兩種方式有異曲同工之處大家可以看一下這兩個接口就會發現兩者非常之雷同最大的區別在於前者通過userObject持有真實的數據而後者則是由TreeItem的getData來持有在使用的時候才會由相應的TreeViewer傳給ITreeContentProvider從結構來說後者是一個純粹的控制類而TreeNode則是更靈活一些可以作為一個控制類也可以作為一個模型體所以相對而言TreeNode更加靈活一些但從本質上而言兩者並無區別
表面上看來一個TreeViewer將會擁有一個ITreeContentProvider用來取得樹狀的數據模型進而呈現出來但CNF中的樹卻更加靈活在基礎篇中展現的圖中卻表示可以通過擴展點orgeclipseuinavigatornavigatorContent來添加新的結點而且這些與資源並沒有本質的關系它可以與一個具體的文件或者目錄資源綁定也可以與多個具體的文件或者目錄綁定還可以是一個與文件或者目錄無關的模型那麼現在來看一下CNF到底做了哪些事情使得它的模型擴展如此容易呢?
首先啟動Eclipse然後創建一個新的工作區再將CNF相關的代碼以插件的形式導入到這個工作區中開始我們的分析過程
講到這裡要提到Eclipse提供的一個接口IWorkbenchAdapter和IWorkbenchAdapter這兩個接口是有一點點怪的因為從設計的角度來看它將模型與展現層混合在一起違反常見的設計准則但從另一個角度來講它可以減少用戶擴展的內容有利於用戶開發由此可見設計准則並不是一成不變的很多時候它也要在易用性和合理性方面做出適當的妥協這一點也可以在我們自己的設計中加以考慮設計並不是要偏向哪一個方向恰恰相反設計是要在多者之間如易用性穩定性合理性之間取得一個平衡點而不是在各方面都做到完美
另外ITreeContentProvider有一個方法getParent(Object parent)它是用來為一個指定結點找到相應的父親結點從而便於查找和定位而這個方法卻被很多人所忽視開發人員經常會習慣性的直接返回null而且也不會出現什麼錯誤但這個方法其實卻是一個非常有用的方法開發人員在使用Java資源管理器的時候有一個經常使用的功能就是LinkWithEditor這個功能經常是用來在資源管理器上定位當前打開的文件這個功能如此之重要以至於CNF專門為此定義了一個orgeclipseuinavigatorlinkHelper來支持該功能所以請根據實際情況來實現這個方法否則就無法正確的實現相應的功能
以上對TreeViewer的模型進行了簡單的介紹和分析接下來就看一下CNF是如何處理樹模型從而獲得如此高的靈活性
CNF很好的利用了代理模式它自身並沒有提供模型的能力所以它將提供模型的能力仍然交給外部擴展點提供的類它會根據當前要處理的結點以及每個擴展點的表達式來找出能夠處理當前結點的ITreeContentProvider實例然後再將這些實例返回的子結點放入相應的Set中最終以數組的方式返回給TreeViewer從表面上來看可能很難理解正常情況下每個TreeViewer只有一個ITreeContentProvider的模型接口如何能夠從多個實例中取得模型呢?就是由NavigatorContentServiceContentProvider這個代理類完成模型的組合功能
因此只要提供自己的ITreeContentProvidre實現然後通過擴展點掛入即可將各種真實或者虛擬的模型掛入系統
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28448.html