[教學][PureMVC]使用Fabrication與Module溝通

之前有介紹過Pipes Util,雖然Pipes能有效解決PureMVC與Module間溝通的問題,但寫起來實在太繁雜了,在此介紹一個簡單又好用的工具─Fabrication,Fabrication一樣是PureMVC的Util,最大的特徵是能簡化PureMVC的撰寫,包括宣告跟註冊事件,且最令人感心的是連Pipes都簡化了,不用再宣告一大堆管子、連結器什麼有的沒的,只要用PureMVC類似的Notification機置就能完成,寫起來真的是方便許多。

寫個簡單範例,這個範例跟上次的PureMVC + Pipes功能相同,可以拿來做個比較

程式架構

2009-04-08_182938.jpg

Main為Loader,MyModule為Loadee,程式為實做Main跟MyModule溝通

在Fabrication內,Facade會被隱藏起來,所以是沒有Facade的Class,取而代之的是一開始進入的StartupCommand,為了管理Notification,範例另存一個常數的Class,並放在common,方便所有Module操作

<?xml version="1.0" encoding="utf-8"?>
<fab:FlexApplication
xmlns:fab="org.puremvc.as3.multicore.utilities.fabrication.components.*" 
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="init();" fontSize="12">

<mx:Script>
<![CDATA[
import idv.gd.hellofabrication.shell.controller.ApplicationStartupCommand;

override public function getStartupCommand():Class
{
return ApplicationStartupCommand;
}
]]>
</mx:Script>

<fab:FlexModuleLoader id="moduleLoader" x="317"/>

<mx:TextInput id="sendMsg"  width="160" x="0" y="30"/>
<mx:Button id="sendBtn" label="Send" y="30" x="168"/>
<mx:Label x="0" y="2" text="Shell"/>
<mx:Button x="235" y="30" label="Info" id="infoBtn"/>
</fab:FlexApplication>

首先繼承Fabrication內的FlexApp(AIR用AirApp),在一開始指定要呼叫的起始命令,要注意的是StartCommand的前置詞會被Fabrication設成ClassName,這是用來識別Shell跟Module的,所以在命名上小心別重覆了

由於沒有Facade,所以透過StartupCommand來宣告所有的controller,由於StartupCommand正常上只會被執行一次,所以不必憺心會重覆宣告(範例僅用到registerMediator)

package idv.gd.hellofabrication.shell.controller
{
import idv.gd.hellofabrication.shell.view.ApplicationMediator;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.command.SimpleFabricationCommand;

public class ApplicationStartupCommand extends SimpleFabricationCommand
{               
override public function execute(notification:INotification):void
{
var main:Main = notification.getBody() as Main;

registerMediator(new ApplicationMediator(main));                        
}
}
}

Mediator需繼承自FlexMediator,Fabrication的Mediator能透過onRegister去註冊方法,取代PureMVC原本的interestedList跟Switch case,只要方法下reactTo、respondTo關鍵字就能分別聽到Event跟Notification,這是Fabrication最特殊的Reflexive功能,比較可惜的是由於Reflexive是透過describeType倒出,所以方法只能下Public,失去程式封裝的原則,寫起來是很方便,但要小心拼錯是不會跳錯誤的,改常數名字時也是一個大工程...。(還是可用PureMVC的方式宣告,FlexMediator是繼承自Mediator)

格式大致如下:

reactTo <物件> <事件名> (event:<對應事件>)

respondTo <Notification名稱> (note:INotification)

再來就是最重要的Module溝通了,Fabrication能藉由Pipes做Module溝通(Pipes要另外匯入),只要一開始有把Module的defaultRouteAddress跟router設為Shell的applicationAddress、applicationRouter即可,之後再透過routeNotification來傳送通知,當然也能指定要送給誰,在routeNotification的第四個參數可決定傳送對象,"*"為全部,過濾格式為 <Class name/ instance name>,Class name就是我們之前宣告的StartupCommand的前置詞,也能使用flexModule.moduleAddress.getClassName()來取得Module名稱

ApplicationMediator

package idv.gd.hellofabrication.shell.view
{
import flash.events.MouseEvent;

import idv.gd.hellofabrication.common.RouteConst;

import mx.controls.Alert;
import mx.controls.Button;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.components.FlexModule;
import org.puremvc.as3.multicore.utilities.fabrication.components.FlexModuleLoader;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.mediator.FlexMediator;

public class ApplicationMediator extends FlexMediator 
{               
public static const NAME:String = "ApplicationMediator";        

public function ApplicationMediator(viewComponent:Main)
{
super(NAME, viewComponent);             
}

override public function onRegister():void
{
super.onRegister();

moduleLoader.router = this.applicationRouter;
moduleLoader.defaultRouteAddress = this.applicationAddress;

moduleLoader.url = "MyModule.swf";

var vm:FlexModuleLoader = new FlexModuleLoader();
}

/**
* view內所有的元件使用  reactTo<ComponentName + EventName> 註冊(Fabrication會自動解析,監聽)
*/
public function reactToSendBtnClick(event:MouseEvent):void
{
var module:FlexModule = FlexModule(moduleLoader.child);

//第四個參數決定傳送給誰,"*"為全部,過濾格式為 <Module name/ Module child instance name>
routeNotification(RouteConst.SHELL_MESSAGE, main.sendMsg.text, null, "MyModule/*" );
}       

public function reactToInfoBtnClick(event:MouseEvent):void
{
var msg:String = "";
var module:FlexModule = FlexModule(moduleLoader.child);

msg += "Main Name: " + this.applicationAddress.getClassName() + "\n";                  
msg += "Module Name: " + module.moduleAddress.getClassName();

Alert.show(msg);
}                                               

/**
* 將mediator感興趣的notification寫成 function,格式為:respondTo<NotificationName>
*/
public function respondToModuleMessage(note:INotification):void
{
main.sendMsg.text = note.getBody().toString();
}

/**
* 元件要設 get,使用reactionTo參照的元件,modifier要設為 public
*/             
public function get sendBtn():Button
{
return main.sendBtn;
}

public function get moduleLoader():FlexModuleLoader
{
return main.moduleLoader;
}

public function get infoBtn():Button
{
return main.infoBtn;
}

protected function get main():Main
{
return viewComponent as Main;
}
}
}

要接收RountNotification一樣用RespondTo來接收,跟Pipes的概念不太一樣,沒有獨立的溝通管道,而是直接整合成PureMVC通知架構,這樣也是有好有壞,有時會搞不清楚通知是來自Module還是自己

MyModuleMediator

package idv.gd.hellofabrication.modules.myModule.view
{
import flash.events.MouseEvent;

import idv.gd.hellofabrication.common.RouteConst;

import mx.controls.Button;

import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.utilities.fabrication.patterns.mediator.FlexMediator;

public class MyModuleMediator extends FlexMediator
{               
public static const NAME:String = "ApplicationMediator";        

public function MyModuleMediator(viewComponent:MyModule)
{
super(NAME, viewComponent);             
}

public function respondToShellMessage(note:INotification):void
{
myModule.sendMsg.text = note.getBody().toString();
}

public function reactToSendBtnClick(event:MouseEvent):void
{
routeNotification(RouteConst.MODULE_MESSAGE, myModule.sendMsg.text, null, "*");
}       

protected function get myModule():MyModule
{
return viewComponent as MyModule;
}
                public function get sendBtn():Button
{
return myModule.sendBtn;
}
}
}

範例要加掛PureMVC MultiCore、Pipes跟Fabrication的library

原始檔下載:http://gwbasic12.googlepages.com/Practice_Fabriation.zip

Google code:http://code.google.com/p/fabrication/

Drunks Blog:CodeDrunks Blog

0 意見 :: [教學][PureMVC]使用Fabrication與Module溝通