天天看點

有關于as3的puremvc架構實作和了解

今天學習PureMVC,看了教程,寫了Demo,記錄并分享學習過程。

教程參考:http://puremvc.org/component/option,com_wrapper/Itemid,183/

PureMVC使用觀察者模式,将代碼分離為三個離散的層:模式、視圖和控制器,這三部分由三個單例模式類管理,分别是Model、View和Controller,三者合稱為核心層或核心角色。PureMVC中還有另外一個單例模式類——Façade,Façade提供了與核心層通信的唯一接口,以簡化開發複雜度。

PureMVC的通信不采用Flash的EventDispatcher/Event,是因為PureMVC可能運作在沒有FlashEvent和EventDispatcher類的環境中。

PureMVC架構示意圖:

由圖很明顯可以知道PureMVC的層次結構:

  1. Model層:由Value Object和Proxy組成。Proxy負責操作資料模型,與遠端服務通信存取資料。Proxy發送Notification,但不接收Notification,比如Proxy從遠端服務接收到資料或資料被更新時,都要發送Notification告訴系統,由View層和Controller層來接收并做相應回報到界面。
  2. View層:由UI和對應的Mediator組成。Mediator儲存一個或多個View Component的引用,通過View Component自身提供的API管理它們。Mediator既能發送Notification也能接受Notification,主要職責是處理View Component派發的事件和系統其它部分發出來的Notification(通知)。
  3. Controller層:由Command和Facade組成。Command實作應用程式的業務邏輯。可以擷取Proxy對象并與之互動,發送Notification,執行其它的Command。用于複雜的或系統範圍的操作,如應用程式的“啟動”和“關閉”。Command接收通知也可以發出通知。實際Command類可以繼承自SimpleCommand(對于單獨業務),也可以繼承自MacroCommand(如果需要執行多個業務邏輯)。Facade類應用單例模式,負責初始化核心層(Model,View和Controller),并能通路它們的public方法。在實際的應用中,隻需要繼承Facade類建立一個具體的Facade類(一般命名為ApplicationFacade)就可以實作整個的MVC模式,并不需要在代碼中導入編寫Model,View和Controller的類。

Facade和Proxy隻能發送Notification,Mediator既可以發送也可以接收Notification,Notification被映射到Command,同時Command也可以發送Notification,這是一種“釋出/訂閱”機制,所有的觀察者都可以收到相同的通知。例如多個書刊訂閱者可以訂閱同一份雜志,當雜志有新刊物出版時,所有的訂閱者都會被通知。

下面開始寫例子PureMVCDemo:完成使用者登入在背景進行驗證合法性,并回報給前台。

版本說明:

Flex:Flex4

ActionScript:ActionScript 3.0

Java JDK:jdk1.6.0_20

PureMVC:PureMVC_AS3_2_0_4,官方網站提供多種語言的資源包下載下傳,在這裡用ActionScript版本,下載下傳連結http://trac.puremvc.org/PureMVC_AS3/。将下載下傳到的資源檔案PureMVC_AS3_2_0_4.swc拷貝到Flex工程的libs目錄下即可。

工具及環境和Java背景服務應用的建立過程介紹:詳見我的上篇文章,BlazeDS實作Flex和Java通信的Demo

1、背景Java服務端項目工程PureMVCDemo組成:

相應代碼:

UserVO.java

package net.dreamhui.java;

public class UserVO {

         publicString userName;

         publicString passWord;

         publicUserVO()

         {

                  //和ActionScript對應得構造方法

         }

         //getters& setters

         publicString getUserName() {

                  returnuserName;

         }

         publicvoid setUserName(String userName) {

                  this.userName= userName;

         }

         publicString getPassWord() {

                  returnpassWord;

         }

         publicvoid setPassWord(String passWord) {

                  this.passWord= passWord;

         }

}

LoginUser.java

package net.dreamhui.java;

public class LoginUser {

         publicUserVO currentUser;

         privateString uName;

         privateString pWord;

         //Flex端要調用的服務

         publicUserVO login(UserVO par_user)

         {

                  //UserVOpar_user2 = UserVO(par_user);

                  uName= par_user.userName;

                  pWord= par_user.passWord;

                  if(uName.equalsIgnoreCase("wwh")&&pWord.equalsIgnoreCase("wwh"))

                  {

                          returnpar_user;

                          //return"歡迎使用者:"+uName;

                  }

                  else{

                          returnnull;

                          //return"使用者名或密碼錯誤,請重新輸入";

                  }

         }

}

配置檔案remoting-config.xml要添加的内容:

<destinationid="loginUser">

                  <properties>

                          <source>net.dreamhui.java.LoginUser</source>

                  </properties>

</destination>

2,前台Flex工程PureMVCDemo工程組成:

相應代碼(按照開發流程):

LoginPanel.mxml

<?xml version="1.0"encoding="utf-8"?>

<s:Panelxmlns:fx="http://ns.adobe.com/mxml/2009"

         xmlns:s="library://ns.adobe.com/flex/spark"

         xmlns:mx="library://ns.adobe.com/flex/mx"

         title="請登陸"currentState="initState"

         creationComplete="lvcreationComplete(event)">

         <!--~~~~~~~~~~~~~~~~~~~~~~Script~~~~~~~~~~~~~~~~~~~~~~-->

         <fx:Script>

                  <![CDATA[

                          importmx.controls.Alert;

                          importmx.core.UIComponent;

                          importmx.events.FlexEvent;

                          importmx.events.ValidationResultEvent;

                          importmx.rpc.events.FaultEvent;

                          importmx.rpc.events.ResultEvent;

                          importmx.validators.Validator;

                          importnet.dreamhui.controller.events.LoginEvent;

                          importnet.dreamhui.model.vo.UserVO;

                          privatevar validObjs:Array;

                          [Bindable]

                          privatevar _currUser:UserVO;// = new UserVO();

                          protectedfunction lvcreationComplete(event:FlexEvent):void

                          {

                                   validObjs= [unSV,pwSV];

                          }

                          protectedfunction submit(event:MouseEvent):void

                          {

                                   varvalidatorResults:Array;

                                   validatorResults= Validator.validateAll(validObjs);

                                   if(validatorResults.length== 0)

                                   {

                                            varuser:UserVO = new UserVO();

                                            user.userName= uName.text;

                                            user.passWord= pWord.text;

                                            var lgEvent:LoginEvent= new LoginEvent(LoginEvent.LOGIN_USER);

                                            lgEvent.data= user;

                                            dispatchEvent(lgEvent);

                                            //Alert.show("dispatchEvent");

                                            //派發事件

                                            }

                                   else

                                   {

                                            //定義校驗出錯事件

                                            varvEvent:ValidationResultEvent;

                                            //取出第一個出錯事件

                                            vEvent= validatorResults[0] as ValidationResultEvent;

                                            //将光标定位到第一個出錯的元件上

                                            (vEvent.target.sourceas UIComponent).setFocus();

                                   }

                          }

                          [Bindable]

                          publicfunction get currUser():UserVO

                          {

                                   return_currUser;

                          }

                          publicfunction set currUser(value:UserVO):void

                          {

                                   _currUser= value;

                          }

                  ]]>

         </fx:Script>

         <!--~~~~~~~~~~~~~~~~~~~~~~states~~~~~~~~~~~~~~~~~~~~~~-->

         <s:states>

                  <s:Statename="initState"/>

                  <s:Statename="loginState"/>

         </s:states>

         <!--~~~~~~~~~~~~~~~~~~~~~~Declarations~~~~~~~~~~~~~~~~~~~~~~-->

         <fx:Declarations>

                  <!--定義使用者名和密碼的輸入校驗類-->

                  <mx:StringValidatorid="unSV"

                          source="{uName}"

                          property="text"

                          required="true"

                          maxLength="10"

                          tooLongError="使用者名最長為10位"

                          requiredFieldError="請填寫使用者名"/>

                  <mx:StringValidatorid="pwSV"

                          source="{pWord}"

                          property="text"

                          required="true"

                          maxLength="10"

                          tooLongError="密碼最長為10位"

                          requiredFieldError="請填寫密碼"/>

         </fx:Declarations>

         <!--~~~~~~~~~~~~~~~~~~~~~~UIComponents~~~~~~~~~~~~~~~~~~~~~~-->

         <mx:FormincludeIn="initState">

                  <mx:FormItemlabel="使用者名" >

                          <s:TextInputid="uName" />

                  </mx:FormItem>

                  <mx:FormItemlabel="密碼" >

                          <s:TextInputid="pWord" displayAsPassword="true" />

                  </mx:FormItem>

                  <mx:FormItem>

                          <s:Buttonid="submitBtn" click="submit(event)"  label="登陸"right="0" />

                  </mx:FormItem>

         </mx:Form>

         <s:HGroupincludeIn="loginState" top="20" left="10" >

                  <s:Label  text="歡迎尊貴的使用者:"/>

                  <s:Label  id="cuName" text="{currUser.userName}"/>

         </s:HGroup>

</s:Panel>

UserVO.as

package net.dreamhui.model.vo

{

         [Bindable]

         [RemoteClass(alias="net.dreamhui.java.UserVO")]

         publicclass UserVO

         {

                  privatevar _userName:String;

                  privatevar _passWord:String;

                  publicfunction UserVO()

                  {

                  }

                  //getters& setters

                  publicfunction get userName():String

                  {

                          return_userName;

                  }

                  publicfunction set userName(value:String):void

                  {

                          _userName= value;

                  }

                  publicfunction get passWord():String

                  {

                          return_passWord;

                  }

                  publicfunction set passWord(value:String):void

                  {

                          _passWord= value;

                  }

         }

}

LoginEvent.as

package net.dreamhui.controller.events

{

         importflash.events.Event;

         publicclass LoginEvent extends Event

         {

                  privatevar _data:Object;

                  publicstatic const LOGIN_USER:String = "loginUser";

                  publicfunction LoginEvent(type:String, bubbles:Boolean=false,cancelable:Boolean=false)

                  {

                          super(type,bubbles, cancelable);

                  }

                  publicfunction get data():Object

                  {

                          return_data;

                  }

                  publicfunction set data(value:Object):void

                  {

                          _data= value;

                  }

         }

}

LoginPanelMediator.as

package net.dreamhui.view

{

         importnet.dreamhui.controller.ApplicationFacade;

         importnet.dreamhui.controller.events.LoginEvent;

         importnet.dreamhui.model.LoginProxy;

         importnet.dreamhui.model.vo.UserVO;

         importnet.dreamhui.view.ui.LoginPanel;

         importmx.controls.Alert;

         importorg.puremvc.as3.interfaces.IMediator;

         importorg.puremvc.as3.interfaces.INotification;

         importorg.puremvc.as3.patterns.mediator.Mediator;

         publicclass LoginPanelMediator extends Mediator implements IMediator

         {

                  publicstatic const NAME:String = "LoginPanelMediator";

                  publicfunction LoginPanelMediator(viewComponent:LoginPanel)

                  {

                          super(NAME,viewComponent);

                          viewComponent.addEventListener(LoginEvent.LOGIN_USER,login);

                          //添加視圖事件監聽,當點選“登入”按鈕時觸發

                  }

                  publicfunction login(event:LoginEvent):void

                  {

                          //Alert.show("LoginPanelMediatorlogin");

                          varlgUser:UserVO = event.data as UserVO;

                          sendNotification(ApplicationFacade.USER_LOGIN,lgUser);

                  }

                  overridepublic function listNotificationInterests():Array

                  {

                          return[LoginProxy.LOGIN_YES,LoginProxy.LOGIN_NO];

                  }

                  overridepublic function handleNotification(notification:INotification):void

                  {

                           switch(notification.getName())

                          {

                                   caseLoginProxy.LOGIN_YES:

                                            //通知來源LoginProxy,如果使用者名和密碼正确

                                            loginPanel.currUser= notification.getBody() as UserVO;

                                            loginPanel.currentState= "loginState";

                                            break;

                                   caseLoginProxy.LOGIN_NO:

                                            //通知來源LoginProxy,如果使用者名或密碼錯誤或遠端服務調用失敗

                                            //Alert.show("使用者名或密碼錯誤,請重新填寫");

                                            Alert.show(notification.getBody().toString());

                          }

                  }

                  protectedfunction get loginPanel():LoginPanel

                  {

                          returnviewComponent as LoginPanel;

                  }

         }

}

LoginCommand.as

package net.dreamhui.controller.business

{

         importnet.dreamhui.model.LoginProxy;

         importnet.dreamhui.model.vo.UserVO;

         importmx.controls.Alert;

         importorg.puremvc.as3.interfaces.INotification;

         importorg.puremvc.as3.patterns.command.SimpleCommand;

         publicclass LoginCommand extends SimpleCommand

         {

                  overridepublic function execute(notification:INotification):void

                  {

                          //Alert.show("LoginCommandexecute");

                          varlgUser:UserVO = notification.getBody() as UserVO;

                          //擷取通知攜帶參數,類型為Object,轉換為需要的類型

                          varlgProxy:LoginProxy = facade.retrieveProxy(LoginProxy.NAME) as LoginProxy;

                          //檢索到負責遠端過程調用的業務代理LoginProxy

                          lgProxy.userLogin(lgUser);

                           //調用遠端過程,對調用過程的結果處理,在LoginProxy裡面

                  }

         }

}

LoginProxy.as

package net.dreamhui.model

{

         importmx.rpc.events.FaultEvent;

         importmx.rpc.events.ResultEvent;

         importmx.rpc.remoting.RemoteObject;

         importmx.controls.Alert;

         importnet.dreamhui.model.vo.UserVO;

         importorg.puremvc.as3.interfaces.IProxy;

         importorg.puremvc.as3.patterns.proxy.Proxy;

         publicclass LoginProxy extends Proxy implements IProxy

         {

                  publicstatic const NAME:String = "LoginProxy";

                  publicstatic const LOGIN_YES:String = "loginYes";

                  publicstatic const LOGIN_NO:String = "loginNo";

                  //聲明常量,避免手誤導緻編譯運作錯誤

                  privatevar loginService:RemoteObject;

                  publicfunction LoginProxy()

                  {

                          super(NAME,new UserVO());

                          loginService= new RemoteObject();

                          loginService.destination= "loginUser";

                          //初始化遠端過程調用的RemoteObject執行個體

                          loginService.addEventListener(FaultEvent.FAULT,onFault);

                          loginService.login.addEventListener(ResultEvent.RESULT,onResult);

                          //給遠端過程調用添加事件監聽,在監聽函數裡對調用傳回結果做處理

                  }

                  publicfunction userLogin(par_U:UserVO):void

                  {

                          //Alert.show("LoginProxyuserLogin");

                          loginService.login(par_U);

                          //調用服務端的業務處理方法

                  }

                  protectedfunction onFault(event:FaultEvent):void

                  {

                          //Alert.show("onFault");

                          sendNotification(LOGIN_NO,event.fault.faultDetail);

                  }

                  protectedfunction onResult(event:ResultEvent):void

                  {

                          //Alert.show("onResult");

                          if(event.resultas UserVO == null)

                          {

                                   //傳回null,調用成功,但拒絕登陸成功,發出通知LOGIN_NO

                                   sendNotification(LOGIN_NO,"使用者名或密碼錯誤,請重新輸入");

                          }

                          else

                          {

                                   //傳回正常UserVO,調用成功,登陸成功,發出通知LOGIN_YES

                                   sendNotification(LOGIN_YES,event.resultas UserVO);

                          }

                  }

         }

}

ApplicationFacade.as

package net.dreamhui.controller

{

         importorg.puremvc.as3.interfaces.IFacade;

         importorg.puremvc.as3.patterns.facade.Facade;

         importnet.dreamhui.controller.business.StartupCommand;

         importnet.dreamhui.controller.business.LoginCommand;

         publicclass ApplicationFacade extends Facade implements IFacade

         {

                  publicstatic const STARTUP:String = "startUp";

                  publicstatic const USER_LOGIN:String = "userLogin";

                  publicstatic function getInstance():ApplicationFacade

                  {

                          if(instance== null)

                          {

                                   instance= new ApplicationFacade();

                          }

                          returninstance as ApplicationFacade;

                  }

                  overrideprotected function initializeController():void

                  {

                          super.initializeController();

                          registerCommand(STARTUP,StartupCommand);

                          registerCommand(USER_LOGIN,LoginCommand);

                  }

                  publicfunction startup(app:PureMVCDemo):void

                  {

                          sendNotification(STARTUP,app);

                  }

         }

}

StartupCommand.as

package net.dreamhui.controller.business

{

         importorg.puremvc.as3.patterns.command.MacroCommand;

         publicclass StartupCommand extends MacroCommand

         {

                  overrideprotected function initializeMacroCommand():void

                  {

                          addSubCommand(ModelPreCommand);

                          addSubCommand(ViewPreCommand);

                  }

         }

}

ModelPreCommand.as

package net.dreamhui.controller.business

{

         importnet.dreamhui.model.LoginProxy;

         importorg.puremvc.as3.interfaces.INotification;

         importorg.puremvc.as3.patterns.command.SimpleCommand;

         importorg.puremvc.as3.patterns.observer.*;

         publicclass ModelPreCommand extends SimpleCommand

         {

                  overridepublic function execute(notification:INotification):void

                  {

                          facade.registerProxy(newLoginProxy());

                          //注冊應用程式所需要的Proxy

                  }

         }

}

ViewPreCommand.as

package net.dreamhui.controller.business

{

         importnet.dreamhui.view.ApplicationMediator;

         importnet.dreamhui.view.LoginPanelMediator;

         importnet.dreamhui.view.ui.LoginPanel;

         importorg.puremvc.as3.interfaces.INotification;

         importorg.puremvc.as3.patterns.command.SimpleCommand;

         publicclass ViewPreCommand extends SimpleCommand

         {

                  overridepublic function execute(notification:INotification):void

                  {

                          //注冊應用程式的View視圖和對應的Mediator

                          varapp:PureMVCDemo = notification.getBody() as PureMVCDemo;

                          facade.registerMediator(newApplicationMediator(app));

                          varlgP:LoginPanel = app.getElementAt(0) as LoginPanel;

                          facade.registerMediator(newLoginPanelMediator(lgP));

                  }

         }

}

PureMVCDemo.mxml

<?xml version="1.0"encoding="utf-8"?>

<s:Applicationxmlns:fx="http://ns.adobe.com/mxml/2009"

         xmlns:s="library://ns.adobe.com/flex/spark"

         xmlns:mx="library://ns.adobe.com/flex/mx"

         minWidth="955"minHeight="600"

         xmlns:ui="net.dreamhui.view.ui.*"

         creationComplete="{facade.startup(this);}">

         <!--~~~~~~~~~~~~~~~~~~~~~~~~Script~~~~~~~~~~~~~~~~~~~~~~~~-->

         <fx:Script>

                  <![CDATA[

                          importmx.controls.Alert;

                          importnet.dreamhui.controller.ApplicationFacade;

                          //聲明并執行個體化控制器ApplicationFacade

                          privatevar facade:ApplicationFacade = ApplicationFacade.getInstance();

                  ]]>

         </fx:Script>

         <!--~~~~~~~~~~~~~~~~~~~~~~~~UIComponents~~~~~~~~~~~~~~~~~~~~~~~~-->

         <ui:LoginPanelid="lgPanel" width="340" height="200"top="20"

                  horizontalCenter="-30"  fontSize="20" />

</s:Application>

ApplicationMediator.as

package net.dreamhui.view

{

         importorg.puremvc.as3.interfaces.IMediator;

         importorg.puremvc.as3.patterns.mediator.Mediator;

         publicclass ApplicationMediator extends Mediator implements IMediator

         {

                  publicstatic const NAME:String = "ApplicationMediator"

                  publicfunction ApplicationMediator(viewComponent:PureMVCDemo)

                  {

                          super(NAME,viewComponent);

                  }

         }

}

上一篇: AS3 事件流
下一篇: as3 時間