云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
先简要地介绍一下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()注册的命令.







只有注册用户登录后才能发表评论。


网站导航: