<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-31  評論-257  文章-0  trackbacks-0
          做Flex做久了做大了,就會覺得之前寫的的Flex代碼開始有點亂,哪怕你寫的規范了,但總覺得結構松散,維護不方便,相信很多人剛開始做Flex的時候,都是想到什么功能,就寫什么功能,或者有些好點的,就先畫了個大體的流程圖之類的,因為現在Flex普及得還不夠,很多人做Flex也是試探階段,不敢用作商業項目或其它大項目,只會用來試水技術層面的,所以都是做些小應用的多,就會忽略了設計一個比較好的框架來開發。所以Flex的開發框架就應運而生了。目前,好的Flex開發框架還不多,官方有個Cairngorm的框架,可能有些人會說這個框架有點復雜,其實不然,對比起Ruby的Rails,Java的Struts,Spring之類的開發框架,就顯得簡單得多了。只要清楚了解要MVC的概念,就會對這些框架并不陌生,但是今天的主角不是Cairngorm,而是另一個Flex框架 PureMVC,如果說Cairngorm復雜的話,那么PureMVC就顯得簡單多了,PureMVC比較輕盈,核心也只有十來個類,是一個輕量級的Flex框架,但PureMVC的通用性還是比較廣的,有PHP的,有Java的有Python的。可能直接說框架的使用會比較抽象,那么就由一個實例來開始講解吧,就用一個PureMVC做的一個MP3播放器。



    先來看看PureMVC的結構圖:



          在圖中,Facade,Model,View,Controller都是PureMVC的四個核心類,都是單例模式的,用戶無需操作那Model,View,Controller類,而用戶只需要操作Facade就夠了,Facade類用來管理其它的三個單例類,顧名思義,那三個類都是分別對應 MVC 模式的那三個元素,Facade也是個單例,它負責創建,激活,調用其它的三個類,管理MVC各屋的生命周期。
          而我們看看Model類,又細分了一個Proxy類出來,我們稱其為代理吧,就是對數據模型的一個代理,負責訪問我們的數據對象(Data Object)也就是Cairngorm中的ValueObject,其實都是同一個概念。而類結構上,對數據操作的代理Proxy類就只有一個,但可以從我們的應用上又分為Local Proxy,Remote Proxy,其實都只是Proxy ,只是根據用戶的應用的不同,在Proxy里面實現不同的功能而已,比如如果你操作本地數據(內存中的數據,并非本地操作系統的文件),你可以寫一些VO的getter/setter直接操作數據,而如果是Remote的數據的話,你可以在Proxy類里定義一些HttpService,URLLoader,WebService等等的訪問遠程數據的API,之后將獲取到的遠程數據放在VO中。
          在Controller類里分出一個叫Command的類來,直接翻譯的話,就是“命令”類,通常這些類都是用來處理一些業務流程,某些算法操作等等的操作。比如現在用戶單擊了“獲取數據”的按鈕,程序將從Proxy類里訪問服務器,服務器返回數據之后,那些都是程序看得懂的數據,比如是XML,而如果數據結構比較復雜,你不可能直接將數據顯示給用戶看吧?那就將解析這些數據的工作交給Command來做,比如寫一個ParseCommand的類,將獲得的XML數據傳遞給該Command,在Command里進行數據的過濾,排列,整理等等的功能。再將組積好后數據交給Mediator來進行顯示,而Mediator,就是下面我們要說的。
          在View類里分出一個Mediator的類,該類是用來對ViewComponent操作的,我們暫且叫它“中介類”吧,為什么叫“中介”呢?其實就是用戶界面(UI)與程序結構邏輯之間的中介,因為用戶在界面上的操作,比如Button的Click事件不是直接反映到Command或者Proxy類上的,而是反映給Mediator類,在Mediator里作一些簡單處理,比如驗證合法性,觸發其它ViewComponent的狀態等,在這里也會將用戶的數據封裝在VO里面,再交由Command或Proxy來進一步處理。基本上Mediator只對用戶的操作或用戶提交的數據進行封裝并簡單預處理,而業務邏輯,存儲服務的就應交給Command和Proxy來做,這樣MVC分工好,使得程序結構比較嚴緊,可讀性強,實現松耦合。當你改變了UI時,只需要對Mediator進行相應的改變就行了,而你改變了業務的邏輯與算法之類的話,也相應的改變Command就可以了,對其它模塊的影響不大。
          在上面這個圖中,沒有列出來的一個很重的類,就是 Notification 類,這個類為什么十分重要,可以說也是PureMVC的潤滑劑,因為他是連接MVC各大部分的一個消息機制,就像是Cairngome里面的CairngomeEvent與FrontController,為了實現更好的松耦合,就是靠這個消息機制,因為各大部分中,很少直接的引用調用,而是以“發消息”(或者說是通知吧)來相互數據交流與通訊,這里是很好的使用了“觀察者模式”,因此,在某一部分改變的處理邏輯的話,只是它所發送的消息沒有改變,或者所偵聽的消息沒有改變,那么就不會影響到其它部分。
          另外要注意幾點,Command類是短生命周期的,也就是說,當有消息通知需要用到該Command進行處理時,Facade就會創建這個Command類,并將數據傳入Command里面進行處理,當處理完成后,其生命周期就會結束,所以不要將一些長生命周期的數據存放在Command里,比如不要將一些狀態數據信息存放在Command里面。還有就是Proxy類只會發送“消息”(通知),而不會接收任何消息,而Mediator與Command則可以發送與接收,所以你不能直接發消息通知Proxy去加載數據,而是通過引用Proxy的實例調用相關的函數。理論就說了一大堆了,我們來看看那個MP3播放器實例吧!

    我們先來看看主程序的代碼,PureMVC的入口點:
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     3                 xmlns:view="com.jiangzone.flex.pureplayer.view.ui.*"
     4                 verticalGap="2"
     5                 layout="vertical" creationComplete="fadace.startup(this)"
     6                 backgroundColor="0x444444">
     7     <mx:Style>
     8         //這里的CSS代碼略去
     9     </mx:Style>
    10    
    11     <mx:Script>
    12         <![CDATA[
    13             import com.jiangzone.flex.pureplayer.ApplicationFacade;
    14            
    15             private var fadace:ApplicationFacade = ApplicationFacade.getInstance();
    16            
    17         ]]>
    18     </mx:Script>
    19     <mx:Box width="131">
    20         <view:ProgressBoard        id="progressBoard" />
    21         <view:ControlBoard         id="controlBoard" />
    22         <view:SongListBoard        id="songListBoard" />
    23     </mx:Box>
    24    
    25 </mx:Application>


    從上面代碼我們看到,定義了一個 facade 這個就是Facade的一個實例,而ApplicationFacade是繼承自Facade類的,這個就是PureMVC的整個架構的控制管理類,因為Facade是一個單例,所以不能直接new 的,所以在ApplicationFacade里面定義了一個靜態方法來獲取它的實例。在程序的createComplete事實觸發的時候,我們就調用facade.startup(this)這個方法,意思就是啟動整個框架。
    這里的代碼都比較簡單,我們再來看看ApplicationFacade的代碼:

     1 package com.jiangzone.flex.pureplayer
     2 {
     3     import org.puremvc.as3.interfaces.IFacade;
     4     import org.puremvc.as3.patterns.facade.Facade;
     5     import org.puremvc.as3.patterns.observer.Notification;
     6    
     7     import com.jiangzone.flex.pureplayer.controller.StartupCommand;
     8    
     9     public class ApplicationFacade extends Facade implements IFacade
    10     {
    11         // Notification name constants
    12         public static const STARTUP:String             = "startup";
    13        
    14        
    15         /**
    16          * Singleton ApplicationFacade Factory Method
    17          */
    18         public static function getInstance() : ApplicationFacade {
    19             if ( instance == null ) instance = new ApplicationFacade( );
    20             return instance as ApplicationFacade;
    21         }
    22        
    23         /**
    24          * Start the application
    25          */
    26          public function startup(app:Object):void
    27          {
    28              sendNotification( STARTUP, app );   
    29          }
    30 
    31         /**
    32          * Register Commands with the Controller
    33          */
    34         override protected function initializeController( ) : void
    35         {
    36             super.initializeController();           
    37             registerCommand( STARTUP, StartupCommand );
    38         }
    39        
    40     }
    41 }


    這里分析一下,在ApplicationFacade類里,我們定義了一個String的常量,這個只是一個消息的類型,跟Flex里的Event的常量一樣的,注意,規范化一點的話,應該將消息類型的字符串都定義為常量,而我在后面的代碼中為了省事就直接用“XXXXX”這樣的字串代替了,還是建義寫成靜態常量。
    我們看到了startup()的代碼了,就是在剛才主程序里調用的那個函數,這里接收了一個主程序的引用。
    我們還看到了有一個initializeController( ) 的函數,當這個ApplicationFacade被實例化加載的時候,會先自動調用initializeController( ) 這個函數,所以,我們應當在ApplicationFacade在被初始化的時候,就對Command進行注冊,說就是注冊,其實也只是將一個Command與一個消息綁定在一起而已。當發送該消息時,Facade就會自動的找到那個Command并實例化執行。
    registerCommand( STARTUP, StartupCommand );這句就是對Command進行注冊的代碼,registerCommand都是父類或接口里面定義的方法,我們先不用管它,STARTUP就是上面定義的一個常量,表示一個消息的類型,StartupCommand這個類就是我定義的一個Command類,這里說白了就是STARTUP這個字符串常量就是一個Key,而StartupCommand就是一個Value,存放在一個數組里面,當有人發送一個STARTUP的消息時,程序就自動生成一個StartupCommand來處理。
    我們再看看startup()這個方法,在剛才的主程序里調用這個方法時,傳入了一個傳入了一個參數this,就是主程序本身,在startup()方法里面,發送了一個消息 sendNotification( STARTUP, app );    sendNotification()這個是發送消息的方法,第一個參數是消息的類型,第二個是可選參數,是消息的內容(消息體),在這里,將主程序的引用作為消息體綁在消息里一起發送了。由于之前在初始化的時候將STARTUP消息類型與StartupCommand綁定在一起了,所以當發送這個消息的時候,StartupCommand將會被通知,所以這時候,程序的流程就跳入到StartupCommand類里面。下面我們來看StartupCommand類的內容:

     1 package com.jiangzone.flex.pureplayer.controller
     2 {
     3     import org.puremvc.as3.interfaces.ICommand;
     4           //這里略去一些import代碼
     5     import com.jiangzone.flex.pureplayer.model.PlayListProxy;
     6    
     7     public class StartupCommand extends SimpleCommand implements ICommand
     8     {
     9         override public function execute( note:INotification ) : void   
    10         {
    11             /**
    12              * 獲取消息體內容,在發送STARTUP消息時,將主程序PurePlayer作為消息體跟隨消息傳送
    13              */
    14             var app:PurePlayer = note.getBody() as PurePlayer;
    15            
    16             /**
    17              * 注冊代理(Model)
    18              */
    19             facade.registerProxy(new SongProxy());
    20             facade.registerProxy(new PlayListProxy());
    21             /**
    22              * 注冊ViewComponents或者UI組件的中介器。
    23              */
    24              facade.registerMediator(new ControlBoardMediator(app.controlBoard));
    25              facade.registerMediator( new SongListBoardMediator(app.songListBoard));
    26              facade.registerMediator(new ProgressBoardMediator(app.progressBoard));
    27              
    28              (facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy).loadPlayList();
    29         }
    30     }
    31 }


    上面的就是一個Command的代碼,注意,一個Command必需要實現ICommand接口,而如果是一個單Command的話,就需要繼承SimpleCommand類,而如果是一個Command鏈的話,就需要實現MacroCommand,至于Command鏈,如果有J2EE基礎的話,也就是Filter的過濾器鏈差不多。這里不多說。大家可以看看PureMVC的官方文檔與API!
    在Command里,都需要覆蓋execute 這個方法,這個方法就是執行你的邏輯代碼的地方,由Facade自動調用,當這個Command所綁定的消息被發送時,Facade就會創建一個Command實例并調用execute方法,方法里還傳入一個INotification參數,就是你所發送的那個消息,里面包含了消息類型名稱與消息體。在這個Command里,我沒有處理什么,因為這個Command用于啟動程序框架的,所以只在這里初始化了一些程序需要用到的資源,如注冊代理與注冊中介器,我們可以看到,注冊代理與注冊中介器的方法與注冊Command的方法不同,注冊Command的話,需要一個消息名稱與一個Command類綁定,而代理與中介器的注冊就不需要與消息綁定,直接將代理與中介器實例化之后進行注冊就可以了。這是由于Command的生產控制不是由用戶來操作的,是由Facade里面的一個工廠方法來對Command實例化并管理的,所以需要與一個消息名稱進行綁定,而代理與中介器就是用戶管理的,通常一個代理就對應一個數據結構,如果有幾個數據結構都比較簡單,就可以在一個Proxy里管理,而同理,中介器也一樣,一個中介器對一個Flex組件,但為一個Button建立一個中介器未名太浪費了,所以我這里都是將MP3分成三個部分,控制按鈕部分,歌曲列表部分,播放進度部分,三個部分用三個中介器。通常這些中介器或者Proxy創建一次就可以了,Facade會將它它存放在數組中,當需要用到時,再由Facade來獲取他們,所以,在注冊代理與中介的時候,先實例化它們再注冊!因為Command是短生命周期,而Proxy與Mediator是長生命周期,所以這里與Command有點區別。在實例化中介器的時候,我傳入一個app.controlBoard的值:
    new ControlBoardMediator(app.controlBoard),就是說,我這個中介器是對應app.controlBoard這個控件,app就是主程序。
    當所有需要的資源都注冊好后,我執行了下面一句代碼:
     (facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy).loadPlayList();
    之前講到,注冊代理時,將代理的實例進行注冊,實際上就只是在Facade里將這個代理實例放進數組里而已,所以用facade.retrieveProxy()這個方法可以再次獲得那個實例的引用,再調用這個代理里的一個方法loadPlayList()來進行加載播放列表。上上上面已經說過,因為Proxy是只可以發信息,不可以收信息,所以你叫Proxy工作的話,只好得到它的引用再調用它的方法來控件它的工作。注意,在Facade重新獲得代理的方法里facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy  你需要指定一個字符串來獲取某一個代理,在編寫每一個代理時,都要為它指定一個name的字符串,而且是代理的唯一標識!這個時候,程序的流程就會跳到代理里運行loadPlayList()這個方法。下面,我們來看看PlayListProxy的代碼:

     1 package com.jiangzone.flex.pureplayer.model
     2 {
     3     import org.puremvc.as3.interfaces.IProxy;
     4           //省略import代碼
     5     import flash.xml.XMLNode;
     6 
     7     public class PlayListProxy extends Proxy implements IProxy
     8     {
     9         //定義一個代理的名字,唯一的標識
    10         public static const NAME:String = 'PlayListProxy';
    11         //定義一個HttpService,用于獲取遠程的數據
    12         private var hs:HTTPService;
    13        
    14         public function PlayListProxy():void{
    15             super(NAME,new Array());
    16             hs = new HTTPService();
    17             hs.addEventListener(ResultEvent.RESULT,onResult);
    18             hs.addEventListener(FaultEvent.FAULT,onFault);
    19         }
    20        
    21         public function get playList():Array{
    22             return data as Array;
    23         }
    24        
    25         public function loadPlayList(url:String = 'jiang/pureplayer/data/playlist.xml'):void{
    26             hs.method = "GET";
    27             hs.resultFormat = "xml";
    28             hs.url = url + '?ranid=' + (new Date()).time;
    29             hs.send();
    30         }
    31        
    32         private function onFault(e:FaultEvent):void{
    33 
    34         }
    35        
    36         private function onResult(e:ResultEvent):void{
    37             var arr:Array = data as Array;
    38             var xmlNode:XMLNode = e.result as XMLNode;
    39             for(var i:String in xmlNode.childNodes){
    40                 var obj:Object = new Object();
    41                 var node:XMLNode = xmlNode.childNodes[i];
    42                 obj["label"= node.attributes.label;
    43                 obj["data"= node.attributes.data;
    44                 arr.push(obj);
    45             }
    46             sendNotification("GET_PLAYLIST_COMPLETE",data);
    47         }
    48     }
    49 }


    很累呀。。。休息一會,抽根煙繼續!

    來分析一下代碼,在該代理被實例化時,會調用super(NAME,new Array());這個父類的方法,其實Proxy的構造函數接收兩個參數,一個是Proxy的唯一標識名字,另一個就是所需要作代理的數據,是一個Object,就是說,你的這個Proxy類要對哪些數據作代理呢?就是這個值傳入的,在Proxy基類里面有一個data的屬性,這個屬性就是存放你的實際數據,所以在我的這個PlayListProxy構造時,我創建了一個Array來作為我的數據,因為我這個代理,是代理一個播放列表數據的,所以我將用Array來存放我的播放列表數據。所以就將new Array()的值交給父類構造器里,父類構造器將會對該Array存放在data這個變量屬性里。由于data是Object類型的,所以我們獲取這個data的時候,還要對其轉換成相應的類型,所以為了方便,我寫了一個getter方法來封裝這個操作:
    1 public function get playList():Array{
    2     return data as Array;
    3 }

    以后可以直接調用playList屬性來獲取Array類型的數據了。
    而在 loadPlayList 這個函數里,接收一個可選參數url,通過HttpService來獲取該url中的xml數據。
    按照上上上上上面說的那樣,Proxy只有一個,但你可以按不同用途分為Local Proxy,與Remote Proxy,而這里它的作用就是Remote Proxy,因為他是操作遠程數據。
    當接收數據成功時,調用了 onResult 方法,里面進行了XML簡單的分析,其實可以將該分析操作交給一個Command來完成,但是這里確實是太簡單的分析了,就沒有必交給Command了,自已來完成吧。當解析完成時,發送了一個消息sendNotification("GET_PLAYLIST_COMPLETE",data);
    這里要說明一下,這里用了發消息來通知其它模塊說我已獲得數據了,你們誰對這個數據有興趣就拿去吧。(本人覺得這樣理解更有趣并容易理解)由于是這個機制,所以無論你界面怎樣改變,中介器怎樣改變,都不會影響到我Proxy,因為我獲得數據時,我不用引用你某一個中介器(如果中介器改變了,則同時要修改Proxy的代碼),我只發送一個消息,你們要則要,不要則罷,所以你界面如何改變的話,只要接收這個消息就可以同樣的得到了數據,而不用因界面的修改而修改Proxy。這樣就可以將Mediator與Proxy松耦了。
    至于,是誰對這個“GET_PLAYLIST_COMPLETE”感興趣呢?我在上上上面說過,Proxy只會發,不會收,所以肯定不是其它Proxy對這消息有興趣,而Command么,Command感興趣的消息都是在Facade里給綁定的,而我們上上上面的代碼中,Facade只綁定了STARTUP這個消息,所以現在唯一下來的,就是中介器了,因為中介器也是可以收與發消息的。如果一個中介器(或者說一個界面組件吧)對一個消息感興趣的話,那就需要在中介器的類里面定義這些感興趣的消息,下面我們來看看一個ControlBoardMediator的中介器的代碼:
     1 package com.jiangzone.flex.pureplayer.view
     2 {
     3     import org.puremvc.as3.patterns.mediator.Mediator;
     4     import org.puremvc.as3.interfaces.IMediator;
     5     import com.jiangzone.flex.pureplayer.view.ui.SongListBoard;
     6     import flash.events.MouseEvent;
     7     import mx.events.ListEvent;
     8     import org.puremvc.as3.interfaces.INotification;
     9     import mx.controls.List;
    10     import mx.collections.ArrayCollection;
    11 
    12     public class SongListBoardMediator extends Mediator implements IMediator
    13     {
    14         public static const NAME:String = "SongListBoardMediator";
    15        
    16         public function SongListBoardMediator(vc:Object):void{
    17             super(NAME,vc);
    18             songListBoard.songList.doubleClickEnabled = true;
    19            
    20             songListBoard.songList.addEventListener(ListEvent.ITEM_DOUBLE_CLICK,onDoubleClick);
    21         }
    22        
    23         public function get songListBoard():SongListBoard{
    24             return viewComponent as SongListBoard;
    25         }
    26        
    27         public function get songList():List{
    28             return songListBoard.songList;
    29         }
    30        
    31         private function onDoubleClick(e:ListEvent):void{
    32             var str:String = (e.target.selectedItem.data as String);
    33             sendNotification("GET_SONG_URL_COMPLETE",str);
    34         }
    35        
    36         override public function listNotificationInterests():Array{
    37             return [
    38                        "GET_SONG_URL",
    39                        "GET_PREV_URL",
    40                        "GET_NEXT_URL",
    41                        "GET_PLAYLIST_COMPLETE"
    42                    ];
    43         }
    44        
    45         override public function handleNotification(note:INotification):void{
    46             switch(note.getName()){
    47                 case "GET_SONG_URL":
    48                     if(songList.selectedItem)
    49 
    50 
    51                         sendNotification("GET_SONG_URL_COMPLETE",songList.selectedItem.data as String);
    52                     break;
    53                 case "GET_PREV_URL":
    54                     if(songList.selectedItem){
    55                         var i:int = songList.selectedIndex;
    56                         i -= 1;
    57                         if(i<0) i = (songList.dataProvider as ArrayCollection).length - 1;
    58                         songList.selectedIndex = i;
    59                         sendNotification("GET_PREV_URL_COMPLETE",songList.selectedItem.data as String);
    60                     }
    61                     break;
    62                 case "GET_NEXT_URL":
    63                     if(songList.selectedItem){
    64                         var i:int = songList.selectedIndex;
    65                         i = (i + 1% (songList.dataProvider as ArrayCollection).length;
    66                         songList.selectedIndex = i;
    67                         sendNotification("GET_PREV_URL_COMPLETE",songList.selectedItem.data as String);
    68                     }
    69                     break;
    70                 case "GET_PLAYLIST_COMPLETE":
    71                     var arr:Array = note.getBody() as Array;
    72                     songList.dataProvider = arr;
    73             }
    74         }
    75     }
    76 }


    在這份代碼中,我們主要看看幾個方法函數,其它的都只是處理邏輯,控制Sound的播放什么的,與PureMVC關系不大了。我們主要看看這幾個方法:
    override public function listNotificationInterests():Array
    override public function handleNotification(note:INotification):void
    先說第一個方法,這個方法返回的是一個數組,我們上面說到,怎么知道中介器對哪些消息感興趣呢?就在這個方法里設置了,這些都是接口里的方法,所以需要override,在這個方法里,直接返回一個字符串數組就可以了,而那些字符串,就是你的消息名稱 的字符串,剛才Proxy中,處理完數據后,發了一個“GET_PLAYLIST_COMPLETE”的消息,并將處理好的數據作為消息體一起發送出去了。
    而在這個Mediator里的listNotificationInterests里,返回一個
    1 return [
    2     "GET_SONG_URL",
    3     "GET_PREV_URL",
    4     "GET_NEXT_URL",
    5     "GET_PLAYLIST_COMPLETE"
    6 ];

    看到沒有?那個數組里面包含了GET_PLAYLIST_COMPLETE這個消息名稱字符串。所以,當有人發送這個消息時,這個中介器就會進行響應,至于對這個消息的響應程序,就在
    override public function handleNotification(note:INotification):void
    這個方法里面寫上消息響應代碼。
    在響應函數里,都用switch(note.getName())來區分處理它所接收到的消息的名稱,再處以不同的處理代碼。

    好了,基本上,整個PureMVC的結構就這樣了,流程是比較簡單,就是用消息(Notification)來圍繞MVC各個部分模塊來開發。這個程序還有其它的中介器類,代理類還有其它的類就不一一列出來了,反正PureMVC工作方式都是一樣的,只是對應的功能邏輯不一樣。

    呼,終于全部寫完了,下面給出整個Flex Project 的 源代碼:
    [down=http://www.jiangzone.com.cn/attachments/month_0806/t200864163352.zip]點擊下載此文件[/down]



    posted on 2008-07-29 14:44 姜大叔 閱讀(4990) 評論(32)  編輯  收藏 所屬分類: Flash/Flex

    評論:
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2008-08-10 11:27 |
    好崇拜哦!!
    樓主,源代碼下載不了哦,能發一份給我嗎?目前我很需要,拜托樓主!!!我的Email:cjc19762338@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-08-10 16:13 | sqw00453579
    好厲害啊``我也想學習```可以給個源代碼嗎```謝謝了```
    我的郵箱``sqw00453579@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-08-20 14:37 | HUIHUI
    的確厲害。 我想學 我也要個源碼 3Q~~~
    我的郵箱:huiqian1984@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-09-04 21:58 | zdcgh
    sysucgh#163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-09-16 10:07 | nova
    向你請教一個問題:用swfloader載入一個swf文件,當這個swf文件中有一個combbox的話,這個combox會有問題。具體就是,在第二次load這個文件的時候,里面的combox不能正常使用,不知道你遇到過嗎?不知你是否能給我指點。
    tieying-sky@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2008-10-28 10:52 |
    求一份源文件!!
    Email:wwj256@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2008-11-04 13:59 |
    求得一分源文件。~謝謝
    zhouyanjie@cdeledu.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-11-05 14:40 | CALM
    求一份源文件。~謝謝
    calm7@sohu.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-11-12 14:38 | 530705296@qq.com
    你好,源碼不能下載啊,是否網址有錯,發一份到我的郵箱530705296@qq.com好嗎?謝謝》  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-11-12 22:40 | 小亂
    求源文件
    yunaiming3@163.com
    萬分感激~~~~~~~~~~~~  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2008-12-02 16:48 | 副萊克斯
    恩,源碼不能下載 ,也給我發一份源碼吧 cjf868@163.com
    萬分感謝!!!  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2008-12-13 10:57 |
    樓主 真是大好人啊 你的這些講解讓我對PureMVC 有了進一步的了解

    感動  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-03-13 18:59 | ltdainiy
    源碼不能下載 ,也給我發一份源碼吧 ltdainiy@163.com
      回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-03-31 09:11 | anither
    源碼不能下載,樓主也給我發一份吧 anither@sohu.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-04-16 20:57 | 長沙滿哥
    zan yi ge  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-05-14 16:00 | ideadawn
    不知道博主還能看見我的回復不,看見的話也麻煩給我U一份吧,謝謝了,ideadawn@126.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-05-25 03:45 | wxz
    完整看了博主的這篇文章,還有有些疑惑,能否email一份源代碼給我,萬分感激!wxz859681117@yahoo.com.cn  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2009-07-12 12:34 | dave
    如果可以的話,也請樓主發一份完整代碼給我,謝謝
    davesong07@gmail.com
      回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-07-16 15:43 | pyd
    樓主都發了那么多份了,也發份給小弟我吧
    急需,麻煩您了
    pyd1053@163.com
    不勝感激啊。。。。。。。  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-07-23 11:06 | 王國金
    您好,樓主,你的源碼不能下載,請你發給我一份好嗎?
    king_wgj@hotmail.com
    謝謝你了!  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-10-22 13:43 | sdd
    不錯,給我一份,整學習中

    kevin51job@hotmail.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2009-11-01 14:22 | beyondpaul
    能給我一份源代碼嗎

    連接失效了··感謝 你


    25893458@qq.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2009-11-08 18:02 | 渴望
    給我一份吧,謝謝
    xyxc.105@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2010-04-02 10:36 | JAM
    講解得很精辟, 樓主一定把源碼看過了吧,要是能把框架的源碼結合進去說明下,想必條理能夠更清晰.   回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2010-07-21 15:49 | 我要源代碼
    求源代碼
    huangfang20065128@163.com
    感謝 你……  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2010-12-13 10:38 | iLinux
    代碼需求好踴躍  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2012-04-23 22:33 | 輕淌
    樓主都發了那么多份了,也發份給小弟我吧
    15891448250@163.com
    不勝感激啊。。。。。。。  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2012-05-09 14:35 | 王斌
    我只想說,樓主真犀利啊,樓主辛苦了哈  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2013-01-29 18:02 | hugangyong
    寫得還可以,但我補充幾點:mvc的好處和壞處,每個貼,每個人講的都大同小異,大家可以找幾個看看。但是從管理學和風險上來講,mvc框架做到了以人為本,因地制宜,何解,很多情況下開發團隊的人員的經驗和特長不一,作為一個好的項目經理,如果運用好這把利劍,那么,他們每個人將發揮自己的優勢,鍛煉自己的信心,對人的發展最有利,其他的好處我不說了,我打個比方,一個剛從學校畢業的有熱情有求知欲但是目前能力不夠的人,如果從縱面上給他分配開發任務,這基本上是浪費了人才的同時增大了風險,最大的弊病是對人的發展極為不利,這樣的結果有三種,一:此人壓力過大,走人,二:此人沒有完成任務,三:此人在別人的幫助下勉強的完成了任務,但耗費了很多不必要的時間。上面幾種情況對人的成長和信心的是不小的毀滅。但是從橫向面上則不一樣,界面的樣式不需要很懂業務,并且可以很快的開發修改,并且有效果,即我們的v,時間有限,這里就不繼續講了  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析[未登錄] 2013-03-24 15:59 | hua
    求源碼啊樓主!
    hua14300@163.com  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2014-09-25 16:38 | rong
    有沒有源碼提供啊,多謝!!!  回復  更多評論
      
    # re: 基于PureMVC的一個Flex MP3播放器分析 2014-09-25 16:38 | rong
    272914287@qq.com
    能不能發份源碼到我郵箱啊,萬分感謝!!  回復  更多評論
      
    主站蜘蛛池模板: 亚洲AV成人片色在线观看| 无码人妻一区二区三区免费| 又粗又长又爽又长黄免费视频| 亚洲另类无码专区首页| 国产亚洲精品影视在线| 亚洲日韩精品无码专区加勒比| 一本色道久久综合亚洲精品蜜桃冫 | 视频一区在线免费观看| 国产精品亚洲精品日韩动图| 美女被爆羞羞网站在免费观看| 麻豆亚洲AV成人无码久久精品| 国产精品亚洲色婷婷99久久精品| 美女啪啪网站又黄又免费| 免费人成网上在线观看| 久久国产美女免费观看精品| 免费毛片在线看不用播放器| 无码人妻久久一区二区三区免费| 性色午夜视频免费男人的天堂 | 亚洲综合国产成人丁香五月激情| 99亚偷拍自图区亚洲| 久久久久亚洲国产AV麻豆| 黄人成a动漫片免费网站| 成年女人A毛片免费视频| 未满十八18禁止免费无码网站 | 曰曰鲁夜夜免费播放视频 | 久久久久成人片免费观看蜜芽| 2021在线永久免费视频| 国产成人免费爽爽爽视频| 亚洲v国产v天堂a无码久久| 亚洲欧洲日产国码av系列天堂 | 免费a级毛片18以上观看精品| 亚洲精品成人区在线观看| 亚洲av永久无码精品漫画| 亚洲成综合人影院在院播放| 亚洲精品无码少妇30P| 一级做a爱片特黄在线观看免费看| 久久国产精品国产自线拍免费| 国产免费毛不卡片| 亚洲 国产 图片| 亚洲国产成人久久精品动漫| 亚洲视频在线观看2018|