之前有介紹過Pipes Util,雖然Pipes能有效解決PureMVC與Module間溝通的問題,但寫起來實在太繁雜了,在此介紹一個簡單又好用的工具─Fabrication,Fabrication一樣是PureMVC的Util,最大的特徵是能簡化PureMVC的撰寫,包括宣告跟註冊事件,且最令人感心的是連Pipes都簡化了,不用再宣告一大堆管子、連結器什麼有的沒的,只要用PureMVC類似的Notification機置就能完成,寫起來真的是方便許多。
寫個簡單範例,這個範例跟上次的PureMVC + Pipes功能相同,可以拿來做個比較
程式架構
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溝通
張貼留言