Flex Viewer 解析(三)Flex Viewer架構解析

gispace發表於2011-05-10

OK!進入主題,本小節我們一起來探究一下Flex Viewer的廬山真面目!

3.1  Flex Viewer主席團

com.esri.viewer.managers包中,彙集了Flex Viewer中所有的Manager。這些Manager各個肩負重任,他們雖隱身幕後,卻是Flex Viewer良好運轉的關鍵,我們不妨稱之為主席團成員。

1)     ConfigManager

Flex Viewer通過配置檔案來組織資料、功能和UIConfigManager的責任是適時讀取配置檔案,對配置檔案進行解析,然後將解析結果分發出去,由其他需要使用配置檔案資料的模組接收。

2)     DataManager

Flex Viewer各個部分之間需要共享資料,比如說WidgetWidget之間資料共享。DataManager提供了一種資料共享的方案,任何模組都可以通過DataManager把資料貢獻出來,供其它模組使用。 DataManager的關鍵職責是把共享資料儲存在記憶體中,任何時候都可以從DataManager獲取需要的共享資料。

3)     MapManager

MapGIS應用的基礎。MapManager解決了Map的問題。MapManager不是對Map的簡單封裝,而是提供了所有與Map相關的操作,比如根據配置檔案載入地圖,放大、縮小這些基本操作,畫圖,在地圖上顯示資訊框,圖層控制等等。如果在某個自定義Widget中,想要畫一個多邊形,不必new一個DrawTool,發個訊息告訴MapManager你想畫個多邊形即可;如果你想在地圖上某個點上顯示一些資訊,同樣發個訊息告訴MapManager就行了。MapManager會很友好地幫我們完很多工作,我們只需發個訊息知會一聲。

4)     ScriptingManager

預留,尚未使用。

5)     SecurityManager

預留,尚未使用。

6)     UIManager

Flex Viewer使用者體驗之所以風格統一,是因為UIManager做了大量的工作。在配置檔案中,有如下指令碼,UIManager會根據這一資訊對UI的樣式進行配置。

<style>

               <colors>

0xFFFFFF,0x333333,0x101010,0x000000,0xFFD700

</colors>

               <alpha>0.8</alpha>

</style>

7)     WidgetManager

顧名思義,WidgetManager是對Widget進行管理的元件。WidgetManagerWidget的管理包括根據配置檔案建立Widget資訊列表、載入Widget、佈局Widget、關閉Widget等。WidgetManager提供四種Widget佈局方式:自由佈局(float)、水平佈局(horizontal)、垂直佈局(vertical)和固定佈局(fix)。自由佈局Widget可以拖動,水平佈局、垂直佈局和固定佈局Widget完全有WidgetManager管理,不可拖動;四種佈局方式中,固定佈局Widget不可改變視窗大小。

3.2  Flex Viewer鬆耦合的關鍵

系統耦合度是決定系統靈活性與可維護性的關鍵。Flex Viewer的鬆耦合設計是其健壯的關鍵因素之一。那麼,是什麼保證了Flex Viewer的鬆耦合呢?

“事件!事件!還是事件!”

事件是Flex Viewer鬆耦合的關鍵。在3.1中多次提到了“訊息”,物化到Flex Viewer中就是事件。不同的模組通過事件彼此互動、傳遞資料,保證了各模組之間的鬆耦合,彼此不必相知,卻能緊密合作。ViewerContainerEventBusAppEvent組成了Flex Viewer事件機制的基礎。當然,Flex Viewer事件機制的基礎是Flex的事件機制。

1)     EventBus

繼承自EventDispatcher,使用了單例模式。EventBus是全域性的事件派發器,為Flex Viewer中的不同模組之間的互動提供便利。有了EventBus,不同模組之間的互動無需彼此呼叫對方的方法,只需派發/監聽訊息即可。

2)     AppEvent

繼承自Event,在Flex Viewer中被用來當做訊息和資料的載體,在不同的模組之間傳遞資料。AppEvent定義了Flex Viewer中需要的所有事件型別,也就是那些公共的字串常量。通常,系統層面需要新增的事件也都定義在AppEvent中。

3)     ViewerContainer

繼承自Group,使用了單例模式,是Flex Viewer中各個模組的容器。Flex Viewer中呼叫ViewerContainer最多的三個方法是:addEventListener()dispatchEvent()showError()。我們可以在任何需要對某類AppEvent事件進行監聽的地方通過addEventListener()方法新增監聽,可以在任何需要派發某類AppEvent事件的地方通過dispatchEvent()方法派發事件,可以在任何需要顯示Error資訊的地方通過showError()方法顯示Error資訊。如果通讀Flex Viewer程式碼,會發現,AppEvent的監聽與派發隨處可見。

Flex Viewer鬆耦合的關鍵因素還有Widget的設計和實現,這部分內容將在後面的小節涉及,在此按下不表。

至此,我們的討論涉及到了Flex Viewer中的絕大部分模組,先來看一下Flex Viewer的整體結構,如圖3.1所示。圖中最下方的Control WidgetsBusiness Widgets尚未提及,我們將在3.4中涉及這部分內容。

 

         3.1 Flex Viewer整體結構

3.3  初始化那些事兒

在瀏覽器位址列輸入Flex Viewer的地址,經過短暫等待,當她華麗麗地展現在我們眼前,你是否想過在這短暫的等待中,Flex Viewer都做了哪些事情呢?本小節我們來探討Flex Viewer初始化那些事兒。注意,我們這裡所說的Flex Viewer初始化,不是Flex概念中元件生命週期的初始化部分,而是指Flex Viewer在可以與使用者互動之前,所做的準備工作。

 

3.2 Flex Viewer初始化過程

3.2小節中,我們強調通過使用事件,Flex Viewer將各模組之間充分解耦。實際上,事件也伴隨著Flex Viewer初始化的整個過程。Flex Viewer的初始化過程如圖3.2所示。

1)     首先觀察一下ConfigManager的構造方法,其中有這樣一句程式碼:

ViewerContainer.addEventListener(ViewerContainer.CONTAINER_INITIALIZED, init);

也就是說,ConfigManager例項在構造期間就通過ViewerContainerEventBus的單例新增了對CONTAINER_INITIALIZED事件的監聽,一旦ViewerContainer在別的地方派發了CONTAINER_INITIALIZED事件,ConfigManager將響應該事件,開始讀取配置檔案、解析配置檔案,構造ConfigData資料,最後將ConfigData連同CONFIG_LOADED事件派發出去,見下面程式碼:

ViewerContainer.dispatchEvent(new AppEvent(AppEvent.CONFIG_LOADED, configData));

2)     我們再觀察一下UIManagerWidgetManagerMapManager的程式碼,在各自的初始化程式碼中,都可以找到下面一句程式碼,此處不再解釋:

ViewerContainer.addEventListener(AppEvent.CONFIG_LOADED, config);

3)     最後,問題的關鍵在於CONTAINER_INITIALIZED事件何時何地被派發?我們觀察一下ViewerContainerinit()方法,其中有下面這句程式碼:

ViewerContainer.dispatch(ViewerContainer.CONTAINER_INITIALIZED);

init()方法是ViewerContainercreationComplete事件的響應方法。也就是說ViewerContainer初始化結束才是Flex Viewer初始化的開始。

Flex Viewer初始化的脈絡已經相當清晰,ConfigManagerUIManagerWidgetManagerMapManager在各自的初始化過程中對相應的事件進行監聽,一旦ViewerContainer初始化完成,派發出CONTAINER_INITIALIZED事件,其它的準備工作將順其自然,水到渠成。

我們注意到,初始化過程所涉及的各個模組都是相互透明的,彼此並不知道有對方的存在,而這些模組之所以能夠親密協作,關鍵就在於它們都只關心事件,事件機制使得這些模組之間實現鬆耦合。實際上,事件充斥著Flex Viewer的各個角落,隨著對Flex Viewer理解的逐漸深入,對這一點的體會將更加明顯。

3.4  Widget設計及實現

 
一個Widget是對一組相關操作的封裝,這些相關操作完成某項特定業務功能。Widget不僅可以呼叫地圖資源,也可以訪問伺服器端資源。Widget基於Flex Module,編譯後是獨立的swf檔案,這樣一來,將具體的業務邏輯封裝在Widget中,減小了系統主體的體積,在業務功能較多時,可顯著縮短系統載入時間。加之面向介面程式設計和依賴注入思想的應用,Flex Viewer中的Widget可以獨立開發,通過配置檔案決定提供哪些Widget,從而決定系統提供哪些業務功能。可以把Widget理解為“外掛”。這種靈活的“外掛”機制是如何實現的呢?下面我們瞭解一下Widget程式設計模型,如圖3.3所示。

 

 

3.3 Widget程式設計模型

Widget分為兩種,Control WidgetBusiness WidgetControl Widget是指控制元件,比如NavigationWidgetHeaderControllerWidgetOverviewMapWidget等,這些Widget提供系統級別的功能,不針對具體業務功能;Business Widget是指業務元件,比如SearchWidgetBookmarWidgetGeoRSSWidget等,這些Widget提供具體業務功能。兩種Widget都繼承自BaseWidget,都由WidgetManager來管理,不同的是,在WidgetManager中有一個WidgetContainer來專門管理Business Widget

兩種Widget有共同的父類BaseWidgetBaseWidget實現了介面IBaseWidget,兩者也就有了共同的介面。WidgetManager通過IBaseWidget來管理Widget,與具體的Widget解耦。Flex Viewer此處使用面向介面程式設計和依賴注入,實現了主體系統與Widget的鬆耦合。

u  IBaseWidget

該介面定義了WidgetManagerWidget進行互動的方法,BaseWidget實現了這個介面。

u  BaseWidget

該類是所有Widget的基類。只要某一元件繼承自BaseWidgetWidgetManager即可對其進行管理。由於BaseWidget繼承自Module,每一個Widget都將編譯成獨立的swf檔案。

但兩種Widget在具體實現上有所不同。Flex ViewerBusiness Widget提供了統一的UI基類和介面,也就是WidgetTemplateIWidgetTemplate。通常情況下,Control Widget都會使用自定義UI,但是這不是必須的。

u  IWidgetTemplate

該介面定義了BaseWidgetWidgetTemplate互動的方法。WidgetTemplate實現了這一介面。

u  WidgetTemplate

該類是IWidgetTemplate的一種預設實現,在具體的Widget實現中,同樣可以使用自定義的WidgetTemplate,只要實現IWidgetTemplate介面即可。WidgetTemplateWidget提供基本UI控制元件,包括視窗皮膚、帶有圖片按鈕的標題欄等。使用Flex Viewer實現的WidgetTemplate,開發人員可以將更多的精力和時間放在實現業務邏輯上。

需要說明的是,Widget的設計在Flex Viewer 1.x版本和2.x版本中有所區別。在1.x中不存在Control Widget,比如選單元件,選單項是可配置的,但是選單元件本身是不可配置的。2.x版本以後,Widget的概念擴大了,Flex Viewer中,凡是能看到的元件都是Widget,這樣一來,控制元件可以像業務元件一樣可配置,比如HeaderControllerWidget,靈活性大大提高。

 

相關文章