架構一個Flex應用程序
使用
Flex的web開發者可能最初會對用戶界面模型感到困惑。雖然傳統的、類似servlet的、請求-響應(request-response)模型將會在
Flex中應用,但是卻存在一種更好的方法。由于ActionScript語言中的“[Binding]”標簽,你可以把你的視圖綁定到模型數據,這樣一來模型的更改就會自動影響到視圖。
Cairngorm 微型架構使這種方法得到形式化,而且它也是那些想要領會如何“讓它們在一起工作”的開發者的一個非常好的起點。在這篇文章中我將描述變量綁定,特性驅動開發和Carigorm在
NoteTag中是如何一起工作的
這里是一個典型的
Flex應用程序可能的架構:

域(Domain)
·組成域模型的所有類。在NoteTag中,它包含了Notes(記錄),Tasks(事務)以及Subscriptions(訂閱)(Subscriptions是相關Notes或Tasks的一個群集(collection))。
模型(Model)
·一個保存域模型的可綁定實例的一個單體(singleton)。在NoteTag中,ModeLocator單體保存了用戶的訂閱清單,用戶的連接,當前的訂閱,當前的記錄以及其他。
視圖(View)
·UI組件(通常來說就是MXML文件,雖然并不總是)。依賴狀態(state-dependent)的UI組件被綁定到ModeLocator的實例變量。如果ModeLocator中數據被標記為“[Bindable]”,那么它的任何改變都會導致UI自動更新。NoteTag中的一個例子就是NoteListView,它顯示了當前訂閱中的記錄列表。如果當前的訂閱或者它的任何一個記錄改變了,那么NoteListView將會自動更新來反應這些改變。
控制器(Controller)
·同事件驅動的Commands一樣執行特性所需的下部構造。NoteTag中的例子包括GetSubscriptionCommand, GetNoteCommand 以及其他。
業務(Business)
·完成域中對象操作的業務邏輯類,經常呼叫遠程服務并且異步返回結果。對大部分NoteTag的業務邏輯來說SubscriptionManager類是entry point。
服務(Service)
·服務層,保存了用來呼叫遠程服務(HTTPService,RemoteService和WebService)的所有類。NoteTag 使用了一個服務工廠(factory)類集合,減輕了對特殊的HTTP服務的部署,這些HTTP服務來自進行HTTP 服務呼叫的組件。
多數應用程序特性都有上面的一些或者全部結構。下面是一個典型特性的工作流程:
1.視圖(view)廣播一個事件。
2.單體控制器(controller)收到這個事件,把它映射到相應的Command,并且執行這個Command。
3.Command委托適當的業務(Business)對象執行業務邏輯。
4.業務(Business)對象執行業務邏輯,可能對不同的Service進行一個或者多個異步呼叫,并且通過分派(dispatch)一個新的事件給Command來返回結果。
5.Command將結果賦給單體模型。
6.綁定到單體模型中的數據的所有視圖都自動更新。
它是如何在一個特定的特性中工作的呢?當用戶從Notes列表(看下面,在屏幕的頂端)中選中了一個Note時,這個Note就會從適當的存儲(Blogger或TypePad)中加載并顯示在編輯器中(看下面,在屏幕的底端):
1.廣播事件當用戶在第一個Note上點擊時,NoteListView分派一個事件,如下:

程序代碼
// NoteListView.mxml
private function getSelectedEntry(event:
ListEvent) : void
{
??var selectedEntry:TagBasedEntry =
????TagBasedEntry(currentFeed.entries[event.rowIndex-1]);
??Application.application.dispatchEvent(
????new GetNoteEvent(selectedEntry.metadata,true));
}
2. 對事件相應因為NoteTag的Front Controller已經把它自身注冊來監聽所有的Command Event,當GetNoteEvent 被分派的時候它將會被通知。

程序代碼
// NoteTagController.as
public class NoteTagController extends FrontController
{
??public function NoteTagController()
??{
????addCommand(LoginEvent.EVENT_LOGIN, LoginCommand);
????addCommand(GetNoteEvent.EVENT_GET_NOTE, GetNoteCommand);
????addCommand(GetTaskEvent.EVENT_GET_TASK, GetTaskCommand);
????addCommand(PostNoteEvent.EVENT_POST_NOTE, PostNoteCommand);
????// more commands...
??}
}
Cairngorm的 Front Controller通過執行適當的command提供了監聽事件和響應事件的基礎構造。
3. 執行 Command為了獲得這個Note,NoteTag需要呼叫存儲了用戶note的blog服務器。實現了Cairngorm的Command接口的GetNoteCommand就像這樣:

程序代碼
// GetNoteCommand.as
internal class GetNoteCommand extends ChainedCommand
{
??public override function execute(event:CairngormEvent):void
??{
????var initialEvent:GetNoteEvent = GetNoteEvent(event);
????var subscriptionManager:SubscriptionManager =
??????ModelLocator.getInstance().subscriptionManager;
????setNextEventHandler(subscriptionManager,
??????handleLoadNote,
??????LoadNoteEvent.EVENT_LOAD_NOTE,
??????onSubscriptionFault,
??????SubscriptionFaultEvent.EVENT_SUBSCRIPTION_FAULT);
????subscriptionManager.loadNote(initialEvent.metadata);
??}
??private function handleLoadNote(event:LoadNoteEvent):void
??{
????// handle result here...
??}
??// ...
}
(你可能已經發現了GetNoteCommand 繼承了 ChainedCommand——這個類使用setNextEventHandler 方法共同進行一系列異步呼叫。在以后的文章里,我將更深入地討論ChainedCommand,并大體說一下異步回應器(responder)。)
4. 執行業務邏輯SubscriptionManager通過執行對tag服務器和blog服務器一系列的HTTP service呼叫來觸發Note的加載。當note被加載完畢時,SubscriptionManager 將分派一個LoadNoteEvent,這個事件將會被GetNoteCommand.handleLoadNote(參見下一條)觸發。
5. 更新模型GetNoteCommand 通過把加載的Note賦給ModelLocator中適當的數據成員來響應事件。

程序代碼
// GetNoteCommand.as
internal class GetNoteCommand extends ChainedCommand
{
??// ...
??private function handleLoadNote(event:LoadNoteEvent):void
??{
????ModelLocator.getInstance().currentNote = event.note;
??}
??// ...
}
6. 更新視圖任何綁定到ModelLocator的currentNote成員的視圖都將會自動更新來反映新的數據。NoteView,負責在編輯器中顯示Note的組件,是這樣的一個視圖:

程序代碼
// NoteView.mxml
<mx:VBox xmlns:mx="
http://www.adobe.com/2006/mxml"
????xmlns:view="com.adobe.kiwi.notetag.view.*"
????xmlns="*">
??<mx:Script>
??<![CDATA[
????import com.adobe.kiwi.notetag.model.*;
????[Bindable] private var model:ModelLocator = ModelLocator.getInstance();
??]]>
??</mx:Script>
??<view:NoteEdit id="noteEditor" width="100%" height="100%"
????note="{model.currentNote}" />
</mx:VBox>
所有的其它特性——發布一個Note,獲得一個Subscription,更新一個Task——會通過同樣的Event-to-Command-to-Model-to-View途徑來實現。Command-specific事件可以從多種內容中被分派,,而不需要知道哪一個視圖會被影響。視圖可以綁定到模型的變化而并不需要知道引發的事件是從什么地方被分派的。由于松耦合,出現了更清潔,更容易維護的代碼。
posted on 2007-02-28 16:55
???MengChuChen 閱讀(390)
評論(0) 編輯 收藏 所屬分類:
flex2Cairngorm