參考資料 : pureMVC 官方網站
也許對於"純"程式設計師來說 pureMVC 才是比較正統的 MVC design pattern 的作法...跟它相處了兩天還是沒辦法對它產生愛啊... 也許它的可攜性比較高...但是我實在看不到它可愛在哪裡...也許它太正統了;也許是因為它都不使用 Flex framework吧...(可能需要慢慢體會...)
先了解它的主要架構就是一對一對的:
• Model vs. Proxy
• View vs. Mediator
• Controller vs. Command
以下是同上篇 [Flex] Cairngorm 練習筆記 一樣的工作改為 pureMVC 寫法
Menu tree:

list.xml :
0. ListVO
1. 從 ListProxy 開始寫
pureMVC 的 Proxy 主要的工作大概就是:
2. ListMediator:對應 List Component 在主要的 mxml 上
Mediator 主要的工作有:
3. ApplicationFacade:MVC 的總代理,它當然是只有一個
所有的 Proxies , Mediators 跟 Commands 註冊、取用與毀滅都在這邊,不過為了"儘量"跟別人沒關係,它這邊除了 Commond 的註冊外,其餘都是寫在 StartupCommand 內。以下幾乎是 ApplocationFacade 的標準寫法。
反正就是先註冊了一個 StartupCommand 然後馬上 Notification 它~~
4. StartupCommand
該初始化的都在這邊完成~~
5. TestPureMVC.mxml
到目前的理解,pureMVC 事件傳遞機制是採用 Observer vs. Notification。如果有註冊成組的 Command 與 Notification ,Notification 被發送時也會執行 Command,然後 viewComponent 採用 as3 的 Event 機制發送 Event 給 Mediator 監聽...反正就是多用 Notification & Command吧...
to be continue....?
也許對於"純"程式設計師來說 pureMVC 才是比較正統的 MVC design pattern 的作法...跟它相處了兩天還是沒辦法對它產生愛啊... 也許它的可攜性比較高...但是我實在看不到它可愛在哪裡...也許它太正統了;也許是因為它都不使用 Flex framework吧...(可能需要慢慢體會...)
先了解它的主要架構就是一對一對的:
• Model vs. Proxy
• View vs. Mediator
• Controller vs. Command
以下是同上篇 [Flex] Cairngorm 練習筆記 一樣的工作改為 pureMVC 寫法
Menu tree:

list.xml :
<?xml version="1.0" encoding="utf-8"?>
<data>
    <list name="AAAA" data="0"/>
    <list name="BBBB" data="1"/>
    <list name="CCCC" data="2"/>
    <list name="DDDD" data="3"/>
</data>
0. ListVO
package com.mvc.model.vo
{
 public class listVO 
 {
  public function listVO(label:String, data:String){
   this.label = label;
   this.data = data;
  }
  public var label:String;
  public var data:String;
 }
}1. 從 ListProxy 開始寫
pureMVC 的 Proxy 主要的工作大概就是:
- 匯集對應 Models 提供方法、屬性給別人使用 ( 建議:給自己或 Command 修改就好 )
 - 要努力跟 Mediator 絕交,不要認識最好
 - 封裝區域邏輯 ( 反正就是弄好資料才給別人 )
 - 只發不收 Notification
 
package com.mvc.model
{
 import mx.rpc.IResponder;
 import mx.rpc.http.HTTPService;
 import mx.collections.ArrayCollection;
 import com.mvc.model.vo.listVO;
 
 import org.puremvc.as3.patterns.proxy.Proxy;
 public class ListProxy extends Proxy implements IResponder
 {
  public static const NAME:String = "listProxy";
  public static const LIST_CHANGED:String ="list_changed";
  
  public function ListProxy()
  {
   super(NAME, new ArrayCollection);
   update();
  }
  public function update():void{
   var httpService:HTTPService = new HTTPService();
   httpService.url="data/list.xml";
   httpService.resultFormat = "e4x";
   var call:Object = httpService.send();
   call.addResponder(this);
  }
  //隱藏的 getter 給自己看的,順便轉換資料型態
  private function get list() : ArrayCollection { 
    return data as ArrayCollection; 
  }
  /**
  * Implemented mx.rpc.IResponder
  * 外面的別用這兩個方法
  */
  public function result( event:Object ):void{
   var xml:XML = XML(event.result);
   var list:ArrayCollection = new ArrayCollection;
   for each (var subxml:XML in xml.list){
    list.addItem( new listVO ( subxml.@name, subxml.@data));
   }
   setData(list);
   //改完就要發 Notification
   sendNotification( LIST_CHANGED, data ); 
  }
  public function fault( obj:Object ):void{
   trace("XML 載入錯誤");
  }
 }
}2. ListMediator:對應 List Component 在主要的 mxml 上
Mediator 主要的工作有:
- 監聽並反應 viewComponent 發送的 Events
 - 可收發與處理 Notifications
 - 避免直接修改 Proxy ,要嘛就是用 Command
 - 其他?...( 跟它還不夠熟 )
 
package com.mvc.view
{
 import com.mvc.model.ListProxy;
 
 import mx.collections.ArrayCollection;
 import mx.controls.List;
 
 import org.puremvc.as3.interfaces.INotification;
 import org.puremvc.as3.patterns.mediator.Mediator;
 public class ListMediator extends Mediator
 {
  public function ListMediator(mediatorName:String=null, viewComponent:Object=null)
  {
   super(mediatorName, viewComponent);
  }
  override public function listNotificationInterests():Array
  {
   //要處理啥訊息都在這邊列好
    return [  
               ListProxy.LIST_CHANGED
             ];  
  }
  
  override public function handleNotification(notification:INotification):void
  {
   //上面有列這邊才收的到喔!
   switch(notification.getName()){
    case  ListProxy.LIST_CHANGED:
     list.dataProvider = notification.getBody() as ArrayCollection; 
   }
  }
  //給自己看的,重點還是轉換物件型態
  private function get list():List {
   return viewComponent as List;
  }
  
 }
}
3. ApplicationFacade:MVC 的總代理,它當然是只有一個
所有的 Proxies , Mediators 跟 Commands 註冊、取用與毀滅都在這邊,不過為了"儘量"跟別人沒關係,它這邊除了 Commond 的註冊外,其餘都是寫在 StartupCommand 內。以下幾乎是 ApplocationFacade 的標準寫法。
package com.mvc
{
 import org.puremvc.as3.patterns.facade.Facade;
 import org.puremvc.as3.interfaces.IFacade;
 import com.mvc.control.StartupCommand;
 public class ApplicationFacade extends Facade implements IFacade
 {
  public static const STARTUP:String = "startup";
   public function ApplicationFacade()
  {
   super(); 
  }
  public static function getInstance() : ApplicationFacade  
  { 
     if ( instance == null ) instance = new ApplicationFacade( ); 
     return instance as ApplicationFacade; 
    } 
   
     override protected function initializeController( ) : void  
    { 
     super.initializeController();
     registerCommand( STARTUP , StartupCommand );
    } 
   
    public function startup( app:TestPureMVC ) : void  
    {  
    sendNotification( STARTUP, app ); 
    }  
 }
}
反正就是先註冊了一個 StartupCommand 然後馬上 Notification 它~~
4. StartupCommand
該初始化的都在這邊完成~~
package com.mvc.control
{
 import com.mvc.model.ListProxy;
 import com.mvc.view.ListMediator;
 
 import org.puremvc.as3.interfaces.INotification;
 import org.puremvc.as3.patterns.command.SimpleCommand;
 public class StartupCommand extends SimpleCommand
 {
  public function StartupCommand()
  {
   super();
  }
  override public function execute(notification:INotification):void{
   //這邊只控制畫面上的list component...- - 它的 id = list
     var list:Object = notification.getBody().list;
   facade.registerMediator( new ListMediator(null, list) ); 
   facade.registerProxy( new ListProxy()); 
  }
 }
}
5. TestPureMVC.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
  width="220" height="200" layout="absolute"
  applicationComplete="facade.startup( this )" >
  <mx:Script>
   <![CDATA[
    import com.mvc.ApplicationFacade;
    private var facade:ApplicationFacade = ApplicationFacade.getInstance();
   ]]>
  </mx:Script>
  <!-- ListMediator 的控制對象-->
 <mx:List id="list" />
</mx:Application>
到目前的理解,pureMVC 事件傳遞機制是採用 Observer vs. Notification。如果有註冊成組的 Command 與 Notification ,Notification 被發送時也會執行 Command,然後 viewComponent 採用 as3 的 Event 機制發送 Event 給 Mediator 監聽...反正就是多用 Notification & Command吧...
to be continue....?
感謝Erin大大的教學~
ReplyDelete看來對於龐大的項目,還是要先找個比較適合的pattern歸宿啊
個人感覺Flex framework的UI部分太臃腫了,而且又難Hack,那些API足以讓我抓狂一天
還是比較喜歡“純”AS project,light-weight的東西,不知哪里有更優的UI呢
我倒蠻喜歡 Flex 的 mxml 編寫方式...XD 好適合懶人啊...
ReplyDeletemxml 不錯!!!
ReplyDelete其實自訂的方式還滿容易的
(感覺上...
pure有點難啃...
多啃幾次
registerCommand的時機
ReplyDelete只能在ApplicationFacade裡面嗎?
如果有非常多的Controller設定的數量...
好像會滿可觀的
registerCommand 並不是一定得在 ApplicationFacade 裡喔!
ReplyDelete很好入門的一篇教學~讚!!
ReplyDelete