云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

当服务端或者客户端的逻辑变化后,有很多种方法来更新视图。我比较推荐使用ModelLocator策略,主要是使用Flex的绑定功能。
通常你的视图与ModelLocator的属性绑定,这些属性可以由命令或者其他的业务逻辑或者其他视图所改变。而一旦这些属性发生了变化,所有与它们绑定的视图都随之变化。
因为很多的Cairngorm的例子都想做得浅显易懂,因此经常是简单地将这些属性做为ModelLocator中的一个暴露给外界的成员变量。而当Cairngorm的应用变得庞大的时候,这往往是不够的。在此我将会专门针对这个问题展示一个例子。这个例子是一个股票市场的显示表。
第一次迭代:将应用运转起来
首先看一下Cairngorm所主张的MVC模式。目前股票市场显示表将只包含一些简单的UI控制。点击“GetQuote”来派发Cairngorm事件,调用命令来请求一个新报价。StockMarketPod.mxml中在Button的Click事件中派发Cairngorm事件。

< mx:Button  label ="Get Quote"  click ="getQuoteForSymbol();" />

相应的脚本代码:

 
import org.nevis.cairngorm.samples.dashboard.events.GetStockQuoteEvent;                                    
private function getQuoteForSymbol() : void
{
    var event : GetStockQuoteEvent 
= new GetStockQuoteEvent( symbolTextInput.text );
    dispatchEvent( event );
}

GetStockQuoteCommand响应并处理这个Cairngorm事件,请求一个业务代理类来报价。

public function execute( event : CairngormEvent ) : void
{
    var symbol : String 
= GetStockQuoteEvent( event ).symbol;
    var delegate : StockMarketDelegate 
= new StockMarketDelegate( this );
    delegate.getQuoteForSymbol( symbol );
}


在实际情况中,需要进行一个远程的服务器端的调用,在Demo中,为简化起见,我注释掉了远程调用的相关代码。这里StockMarketDelegate.as只是对命令进行回调。

public function StockMarketDelegate( responder : Responder )
{
    
//disabled for demo
    
//this.service = ServiceLocator.getInstance().getService( "stockMarketDelegate" );
    this.responder = responder;
}

        
public function getQuoteForSymbol( symbol : String ) : void
{
    
//disabled for demo
    
//var call : AsyncToken = service.getQuoteForSymbol( symbol );
    
//call.resultHandler = responder.onResult;
    
//call.faultHandler = responder.onFault;
    if( symbol == "fail" )
    
{
        responder.onFault();
    }

    
else
    
{
        responder.onResult();
    }

}

我们的StockMarketPod视图只需要两条消息,
1. 股票的报价
2. 错误消息
因为现在是第一次迭代过程中,处理比较简单,因此使用ModelLocator的成员来解决。

public var lastStockQuote : Number;
public var stockQuoteError : String;


在此Demo中,GetStockQuoteCommand命令模拟返回相应的结果。

public function onResult( event : ResultEvent = null ) : void
{
    
//simulate a result from service
    var stockQuote : Number = Math.random() * 50 + 5;
    model.lastStockQuote 
= stockQuote;
    model.stockQuoteError 
= "";
 }

        
public function onFault( event : FaultEvent = null ) : void
{
    model.lastStockQuote 
= NaN;
    model.stockQuoteError 
= "An error occured.";
}

StockMarketPod视图绑定这些成员并进行一些格式化的处理。

<mx:FormItem label="Symbol">
    
<mx:Label text="{ formatQuote( model.lastStockQuote ) }"/>
</mx:FormItem>
<mx:FormItem>
    
<mx:Label text="{ model.stockQuoteError }"/>
</mx:FormItem>

格式化函数的脚本

private function formatQuote( quote : Number ) : String
{
    
return ( isNaN( quote ) ) ? "" : String( quote );
}


现在我们来进行重构并将一些功能从视图中抽取出来到一个可以进行单元测试的工具类中。

第二次迭代,创建符合需求的业务逻辑
现在我们已经有一个可以运行的最简单的应用。当你的应用变得庞大后,将会有很多的限制。你会发现你的ModelLocator非常的臃肿,以致于有时候,你都找不到你所要的成员。甚至会有命名冲突的事情发生。
一个普通的重构方法是封装你的用例图中的成员成为一个业务对象。这个业务对象能够表达业务上下文中需要的视图信息。你可以把业务对象设计得最适合用例图的粒度。在一个大型的应用中,你可能会设计一系列的业务对象来表达你的用例。你的视图将会绑定这些对象或者这些对象的属性上。通过这种方法,ModelLocator与其目标之间的联系更容易,开发者更容易掌握业务逻辑所包含的内容。
在这个Demo中,我们可以把astStockQuote和stockQuoteError这两个成员封装到一个业务对象中。

package org.nevis.cairngorm.samples.dashboard.model
{
    
public class StockQuote
    
{
        [Bindable]
        
public var lastStockQuote : Number;
        [Bindable]
        
public var stockQuoteError : String;
    }

}


这样在ModelLocator中,我们只需要定义一个成员
public var stockQuote : StockQuote = new StockQuote ();
我们的视图也相应修改为:

<mx:FormItem label="Symbol">
    
<mx:Label text="{ formatQuote( model.stockQuote.lastStockQuote ) }"/>
</mx:FormItem>
<mx:FormItem>
    
<mx:Label text="{ model.stockQuote.stockQuoteError }"/>
</mx:FormItem>



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


网站导航: