以前的幾次帖子中,我們都談到了在UI平臺的設計過程中常常會使用的一種設計模式,就是封裝,但是封裝是一種極難把握的模式,而且,單單使用封裝往往也起不到任何設計效果,有時還會畫蛇添足,那么,大師們是怎么使用封裝的呢,我們看看Java領域的例子。
Swing是
由Sun的優秀科學家和Netscape的杰出設計師共同創造出來的卓越的架構。它一生下來就擁有皇族血統,但注定一生都不會取得王位?,F在崇拜
Eclipse設計架構的人比較多(包括我),隨之而來的是對Swing的批評聲也很多(不包括我),其實這是一種錯誤的認識,就像
Smalltalk是一種很優秀但使用較少的語言,VB和Foxpro則屬于那種天生拙劣但使用廣泛的語言。Swing比Eclipse架構早出來好幾
年,后者從前者那里吸取了不少的經驗,也借鑒了很多模式,才會有今天的成就。而直到今天Swing仍然有很多值得我們學習的地方。
再說封
裝,打開JButton的源代碼就會發現,JButton沒有往可憐的Windows界面上畫上任何一筆,換句話說,整個類里面一行繪圖代碼都沒有,這是
為什么?因為JButton是一個Controller的變種,繪圖組件由另一個類提供,這個類以UI名字結尾,在內部包中,且繪圖器在不同的界面風格
下、不同的操作系統、甚至不同的語種下面有不同的實現。這使得JButton類四兩撥千斤,憑一個不變的框架同時實現了跨平臺和可插拔風格。至于它的一些
顯示參數,別著急,既然有C有V不可能沒有M啊,ButtonModel類負責維護JButton的參數。
我們再看卓越的Eclipse,Eclipse比其這種封裝來說就要復雜的多了,我們分成六個環節來講。
1。Eclipse將Windows的繪制方法包裝成SWT,這種包裝很原始,但是很有效,因為Java不好調用Win32API,所以這一步實現了跨平臺。需要注意的是,這種包裝應該屬于簡單的分層,Eclipse編寫了一個操作系統的Facade,OS類,這個類的win32版的源代碼有2734行,顯然是個龐然大物啦。
2。Eclipse把SWT當作它的基本組件來重用,(就好像這是別人寫的東西),它把SWT的組件繼續包裝成JFace,JFace采用真正意義上的 MVC模式,比起緊湊的SWT來要活潑一點。JFace把SWT當成它的View,把Provider的實現當作它的Model,把自己包里的可控的帶有組件邏輯的Viewer類當成Controller。
3。由于SWT被設計用來繪制窗體組件,按照管理,應該有一個包被用來繪制二維圖形,這個工作就交給Draw2D來完成,它被放置在GEF包中,和SWT 處在一個層次。需要注意的是,Draw2D與SWT的組織機制不同(見前面的文章)。
4。Eclipse繼續封裝,因為JFace只解決了高級組件的問題,并不能直接放在Workbench里面用,所以Eclipse制作了Workbench包,這個包把Viewer封裝成ViewPart,它認為Viewer是繪制器,而ContentProvider是Model,所以,像之前的幾次一樣,ViewPart變成了Controller。
5。有了ViewPart也就有了EditorPart,這兩種Part都有可能要顯示Form表單(一
種類似HTML的界面),表單上的控件——理所當然,是由
SWT實現的——與一般意義上的控件有很大的不同,這種不同主要體現在展現方式和事件通知上。Eclipse采取的方式是另做一套內部實現,包裝SWT實
現,比如SWT有一個Button,表單包也有一個表單Button,與Button通過一個Toolkit類轉換。這種方式就是設計模式中提到的
Proxy。
6。現在我們再看看需要繪二維圖的EditorPart,這個部分是通過GEF來實現的,GEF是比JFace和Workbench更嚴格的MVC,它再EditorPart的基礎上再包裝一次,將策略等控件業務與控件繪制分離。
今
天我得到的最重要的一個結論,就是封裝是相對的,MVC也是相對的,因此在JFace看來是Controller的東西在Workbench來看可能是
View,這可能導致在設計時的大量爭議。今天的另一個收獲是發現了封裝也有幾類,我能想到的應該有Facade封裝、Proxy封裝、MVC封裝三種,
你還能想到更多的嗎?
做軟件的泡泡