先简要地介绍一下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()注册的命令.