Iteration::two的基于Flex的开源项目-- Cairngorm store的学习笔记(三)

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






你可能感兴趣的:(Iteration::two的基于Flex的开源项目-- Cairngorm store的学习笔记(三))