先簡要地介紹一下Cairngorm中采用的設計模式:
Cairngorm框架最大的革新是將用戶行為和系統級事件統一地映射為Cairngorm事件.
當組件接收到用戶行為或者系統事件后, 用戶請求被轉換成組件可以傳播的內部事件. RIA中處理用戶請求不需要到服務器去轉一圈.
當用戶行為指定要執行一個功能時, Cairngorm要求廣播一個合適的事件.
在設計模式中命令模式特別適合此種情形. 在這個模式中,?將實現功能的類稱之為命令(Command).
每一個而且是所有的命令提供一個單點入口, 一個execute()方法.
這樣允許第3方調用此命令, 而不需要了解命令具體是如何實現的.
通常這些命令被叫作"Worker", 因為他們承擔了在應用背后進行工作的任務.
我們現在開始根據示例來研究Cairngorm Store.
看一下Cairngorm Store關鍵功能之一: 將商品添加到購物車中.
為實現此功能, 創建一個新的命令類: AddProductToShoppingCartCommand
import?org.nevis.cairngorm.commands.Command;
import?org.nevis.cairngorm.control.Event;
import?org.nevis.cairngorm.samples.store.model.ModelLocator;
import?org.nevis.cairngorm.samples.store.vo.ProductVO;
class?org.nevis.cairngorm.samples.store.command.AddProductToShoppingCartCommand??implements?Command??
{
????public?function?execute(?event?:?Event?):Void
????{
????????var?product?:?ProductVO?=?ProductVO(?event.data.product?);
????????var?quantity?:?Number?=?Number(?event.data.quantity?);
????????ModelLocator.shoppingCart.addElement(?product,?quantity?);
????}????
}
這個類看起來并不復雜. 首先一個具體的類實現了Cairngorm的命令接口.
如果你查看了Cairngorm的源碼, 你會發現這個接口只是簡單地規定了命令必須實現一個方法: execute() 作為入口.
看一下execute()方法的實現, 可以發現事件是如何執行包含ProductVO值對象和數量的命令的.
VO和數量是預先裝載在Event類中的. Event也是一個Caringorm定義的類, 其中包括事件的類型和事件的方法.
購物車屬于客戶端數據, 因此它存放于ModelLocator類中. 所以,命令只是添加適當數量的商品到購物車中, 使用購物車提供的方法.
這就是創建一個簡單功能命令類的所有工作. 命令查詢事件, 獲取事件相關數據.
如果執行的命令更改應用的數據,比如要求在購物車視圖中新增一個商品, 應用需要使用ModelLocater完成更改客戶端數據.
有一個非常重要的設計概念在這里強調一下. 在前面的示例中,
所有復雜的業務邏輯(比如一個購物車可以做什么,不可以做什么)都被封裝在一個類中(稱之為ShoppingCart).
比如: 一個用戶添加一個商品到購物車中, 如果購物車沒有此種商品, 則新增一個, 如果已經存在, 則將數量加1.
Cairngorm并不減輕開發者創建業務對象的工作. 特別之處只是在于它實現業務域的類.
開發者應該從Cairngorm架構中抽離出來, 把業務邏輯從命令中提取出來放入類中.
一個典型的實現方法是進行抽象類的重構. 此項技術的好處在于可以進行單元測試, 書寫API文檔, 使用其他應用開發者可以進行復用.
Caringorm商店中的購物車類是遵循此原則的極好的例子.
借鑒設計模式的思想, Cairngorm對客戶事件的進行響應而不是對服務器HTTP的進行響應,
Cairngorm使用前臺控制(Front Controller)模式作為所有Cairngorm事件的統一入口.
class?org.nevis.cairngorm.samples.store.control.ShopController?extends?FrontController
{
????public?function?ShopController()
???{
???????initialiseCommands();
???}
????
????//----------------------------------------------------------------------------
????public?function?initialiseCommands()
????{
??????addCommand(?ShopController.EVENT_GET_PRODUCTS,?new?GetProductsCommand()?);
??????addCommand(?ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART,?new?AddProductToShoppingCartCommand()?);
??????addCommand(?ShopController.EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART,?new?DeleteProductFromShoppingCartCommand()?);??
??????addCommand(?ShopController.EVENT_FILTER_PRODUCTS,?new?FilterProductsCommand()?);?????
??????addCommand(?ShopController.EVENT_SORT_PRODUCTS,?new?SortProductsCommand()?);?????
??????addCommand(?ShopController.EVENT_VALIDATE_ORDER,?new?ValidateOrderCommand()?);
??????addCommand(?ShopController.EVENT_VALIDATE_CREDIT_CARD,?new?ValidateCreditCardCommand()?);?????
??????addCommand(?ShopController.EVENT_COMPLETE_PURCHASE,?new?CompletePurchaseCommand()?);?????
????}
????
????//-------------------------------------------------------------------------
????public?static?var?EVENT_GET_PRODUCTS?=?"getProducts";
????public?static?var?EVENT_ADD_PRODUCT_TO_SHOPPING_CART?=?"addProductToShoppingCart";
????public?static?var?EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART?=?"deleteProductFromShoppingCart";??
????public?static?var?EVENT_FILTER_PRODUCTS?=?"filterProducts";
????public?static?var?EVENT_SORT_PRODUCTS?=?"sortProducts";
????public?static?var?EVENT_VALIDATE_ORDER?=?"validateOrder";
????public?static?var?EVENT_VALIDATE_CREDIT_CARD?=?"validateCreditCard";
????public?static?var?EVENT_COMPLETE_PURCHASE?=?"completePurchase";????????????
????????
}
構造函數調用
initialiseCommands(), 將廣播的事件委派給相應的命令去處理.
我們看一個添加商品到購物車的例子. 當應用廣播ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART命令時,
前臺控制中下面這行代碼保證AddProductToShoppingCartCommand的execute()方法被調用.
addCommand( ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART, new AddProductToShoppingCartCommand() );
ShopController繼承了Cairngorm中的FrontController基類, 因此可以使用addCommand()來給事件注冊相應的命令.
Cairngorm底層架構完成了剩余部分的工作. 應用中任意地方簡單地廣播適當的事件, Cairngorm確保相應的命令被觸發.
另外需要做的是在Mxml的主入口點創建控制器. 在Cairngorm商店中, 是Main.mxml, 代碼如下:
<control:ShopController id="controller" />
"Control"的命名空間在應用標簽中定義, 指定如下Cairngorm包:
xmlns:control="org.nevis.cairngorm.samples.store.control.*"
你只需要這樣做,就可以保證應用擁有一個前臺控制模式, 響應所有的事件, 并觸發你使用addCommand()注冊的命令.