淺析基于Flex界面的組合SDK
Flex是Sun今后的重點產品,用以對抗Adobe的Flash和微軟的Silverlight。這里將介紹基于Flex界面的組合SDK,可以說頁面還是比較簡潔的。
以下是界面類似我們正在開發的一個產品的主界面,前端展示采用Flex開發,后端系統是基于Java的SOA框架。界面左邊是導航條,右邊是內容區(當然還有其它欄目,在此忽略)。內容區一般由多個UI Part組成,每一個Part利用異步機制從后端獲取數據,此外,它還將接收來自后端的通知消息。整個界面非常符合微軟CAB思想,不過Flex沒有CAB組建,但是可以采用Microsoft用戶控件方式定義一塊一塊內容。界面內容區的UI Part可能會被重用。
在設計中,我想利用界面組合思想來設計,采用該思想的優點有:1)界面分割成不同的組成部分,每一部分實現一個功能,更加符合SRP原則;2)實現每一個UI Part時,只需專注復雜界面中的一塊內容的實現,比較簡單;3)容易實現重用;其缺點有:1)每一個界面由多個UI Part組成,需要維護UI Part之間的聯系;2)新手不太容易看懂界面的實現。
鑒于微軟界面組合諸多優點,我決定將其思想引入到Flex,自己實現一個Composition SDK based on Flex,該SDK實現過程中參考了CAB & SCSF和Prism。
考慮到該軟件需要實現的功能,這個SDK將支持如下功能:
1 UI Part生命周期管理。每一個UI Part在顯示的時候,需要從后端獲取數據,然后監聽數據更新消息,當點擊界面的“Tab 2”時,Tab 1被隱藏并停止監聽消息,Tab 2被顯示。在我看來每一個UI Part具有Activated、Deactivated和Closed生命周期狀態,當處于Activated狀態時,UI Part顯示呈現所需數據,當處于Deactivated狀態時,UI Part被隱藏并停止更新數據,當處于Closed狀態時,UI Part被關閉并停止更新數據,它將被銷毀。生命周期管理功能提出的目的是為了實現生命周期變更驅動數據更新,也就是每一個組件數據更新是由其自身的生命周期狀態決定的,不需要由父節點控制,從而實現更大粒度復用。
2 UI Part組合和動態注入。這個功能允許直接在視圖容器類中定義每一個UI Part,在這種方式中,一旦容器被顯示,則所有的UI Part將被顯示;或者是其中某些UI Part是在運行時被動態注入并呈現的,當容器呈現時,根據需要注入特定的UI Part。
3 Master-Details UI Part支持。Master-Details UI Part是一對特殊的UI Part,當Master UI Part的數據發生變更后,Details UI Part也需要更新,和.NET的Master-Details View是一樣的。
4 采用Hook機制實現,使得在實現1~3功能的時候,可以盡量與標準控件兼容,不必創建自定義控件或者僅需創建非常簡單的自定義控件。Hook機制原理如下:A)每一個功能由一個Hook實現;B)比如LifecycleHook,對于一個葉子節點的組件,當其被顯示/隱藏/關閉時,該Hook要維護其狀態;對于一個容器節點,它除了要維護自己的狀態,還要維護子控件的狀態,比如VBox容器,當VBox被顯示時,其狀態為Activated且其所有一級子節點狀態也是Activated;而對于TabNavigator容器,當其被顯示時,其狀態為Activated且當前選中的Tab的狀態也是Activated,其余Tab的狀態都是Deactivated;C)Hook的創建過程是遞歸的監聽界面根節點onChildAdded/Removed事件;D)SDK提供Hook注冊表和Hook管理器,Hook注冊表定義了每一類型的組件對應的Hook,而Hook管理器定義了每一個控件對應的Hook實例。
5 基于該SDK,每一個視圖的設計由Workspace和UI Part組成,Workspace使用Flex標準容器控件定義了界面的布局;UI Part是界面每一部分功能的實現,自己封裝了生命周期驅動的數據更新。
代碼的設計比較簡單,其結構如下:
ComponentTreeHook是整個Hook機制的核心類,它將遞歸監聽根節點控件的onChildAdded/Removed,當有子節點添加時,遞歸掛載整個控件樹,掛載過程代碼如下:
- /**
- * Create the hooks for current component tree and listen the CHILD_ADD/CHILD_REMOVE
- * events of each component.
- *
- * @param comp The root component of the component tree.
- *
- */
- override public function hook(comp:UIComponent):void
- {
- if(!isHooked)
- {
- super.hook(comp);
- hookComponentTree(component);
- }
- }
- private function hookComponentTree(comp:UIComponent):void
- {
- doComponentTreeHooking(comp, true, hookComponentNode);
- }
- /**
- * Do the hooking for a component tree.
- * @param comp The root component.
- * @param hookComponentFunc The actual hook function.
- *
- */
- private function doComponentTreeHooking(comp : UIComponent, hooked : Boolean, hookComponentFunc : Function) : void
- {
- if(!comp)
- {
- return;
- }
- // Hook the node from top to bottom.
- var queue : Array = [ comp ];
- var tempComp : UIComponent = null;
- var tempContainer : Container = null;
- var tempContainerChildren : Array;
- while(queue.length > 0)
- {
- // Get a component from queue.
- tempComp = queue.shift() as UIComponent;
- if(!tempComp)
- {
- continue;
- }
- // Do the hook for this component.
- hookComponentFunc(tempComp);
- // Get the children of current component and push them to queue.
- tempContainer = tempComp as Container;
- // SmartPart here is treast as a Component.
- if(tempContainer && !(tempContainer is ISmartPart))
- {
- if(hooked)
- {
- tempContainer.addEventListener(ChildExistenceChangedEvent.CHILD_ADD, onChildAdded, false, CompositionEventPriority.CREATE_HOOK);
- tempContainer.addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, onChildRemoved, false, CompositionEventPriority.DESTORY_HOOK);
- }
- else
- {
- tempContainer.removeEventListener(ChildExistenceChangedEvent.CHILD_ADD, onChildAdded);
- tempContainer.removeEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, onChildRemoved);
- }
- tempContainerChildren = tempContainer.getChildren();
- for each(var child : UIComponent in tempContainerChildren)
- {
- queue.push(child);
- }
- }
- }
- }
原文標題:基于Flex的界面組合SDK
鏈接:http://www.cnblogs.com/baihmpgy/archive/2009/09/16/1567387.html;
【編輯推薦】