Flash務實主義(四)——Flash中的MVC

FLASH與傳統環境的不同點

MVC最早在1979年的時候第一次被人提出。不過,當時還不存在網絡應用的概念。之後當萬維網誕生之後,又過了很長時間……

它並不是自誕生就開始流行的,而改變的原因很簡單——因爲兩個極其流行的開發框架包含了這種模式,它們就是:Struts 和 Ruby on Rails。之後,模仿者蜂擁而至。所以,在人們眼裏看來,實際上是先有的Struts,然後纔有的MVC,也無怪乎MVC的概念會始終沾染着Web概 念,乃至和一些框架附加內容牽涉不清。

因爲Struts很好用,別的不說,至少讓HTML顯得乾淨了很多。所以很多人都在用Struts,這未必是因爲需要MVC模式,而是因爲他們需要 Struts。因此,當環境變化後,我們不使用Struts而是在使用一些其他的框架的時候,是否還應該像以前那樣使用MVC框架就成爲了一個問題。因爲 環境不同,即使在其他語言中使用MVC框架很普遍,也不代表在新環境裏同樣應該是如此。

AS3與傳統語言的不同點:

  • AS3是單一語言環境,多層代碼混在一起問題沒那麼嚴重。
  • AS3正常情況都是一次性編譯全部代碼,即使用了MVC框架還是需要一起編譯。單獨編譯一個模塊減少編譯時間有別的辦法,不需要依賴MVC。
  • AS3本身的事件和動態特性和一些框架的功能重複。
  • AS3目前的框架還很不成熟,沒有提供比較醒目的功能。

結果是,至少,目前AS3的MVC框架比起傳統語言並沒有那麼突出的作用,就算用了,也不會像Struts那樣有質的變化。而且,至少在我看來,AS3的框架使用成本卻不見得比Struts低。兩者相減,結果就很麻煩了。

而且,AS3在不使用框架的時候有它自己的優勢,使用框架會毀掉這些優點:

  • 有一個相對還可以的調試器,使用了框架會調試上產生麻煩,主要體現在單步調試步驟變多的問題上。
  • 阻礙使用IDE的功能。以Flex Builder爲例,你可以通過Ctrl+單擊(F4)跳轉到指定方法的具體實現,通過搜索引用面板從方法的實現跳轉到調用方法的位置。使用框架後,這些功能都會失效。
  • Flex framework相關功能會難以使用,諸如綁定。而且,Flex Builder支持拖拽式的將數據接口綁定到視圖的功能,可以部分實現零代碼編程,框架也會阻礙這個過程。

此外,企業應用和網站還好說,遊戲還有另一種情況。遊戲的結構並不同於原來的專門用於呈現數據的結構,可能也就是其中的用戶界面(User Interface)部分和以前的結構比較類似,其他的諸如地圖,諸如人物,無論怎麼想也無法套用MVC框架,首先從效率上就說不過去。舉個例子,一個項 目有3個客戶端人員在開發,一個在做地圖,一個在做戰鬥,一個在做UI。前兩者都和MVC沒什麼關係,結果只有一個人在用MVC框架開發界面……而且,開 發前兩者的時候,開發以及協作難度其實是比開發界面要高的,既然他們都搞定了,爲什麼開發界面的人還必須靠框架輔助才能解決這個問題?

這使得FLASH比起一般的情況,會更加不適合使用MVC框架。

不使用現有框架並非無法實現MVC

既然我在說框架不好用。那麼不用框架,我們又該怎麼做呢?

實際上,如果你只是想實現單純的模型—視圖—控制器(Model View Controller)分工職守,它只是一個架構模式而已。將模型和視圖的代碼分開,並提出控制器的代碼,然後互相調用各自方法就算完事了。Model的 全部引用放在固定的位置,View的引用使用靜態屬性儲存或者用管理類管理,Command可以作爲函數或者類直接初始化並執行,亦可以通過反射。這並不 需要專門的工具類來輔助,附加成本也比較小,自然就可以適用於任何規模的項目。

當然,你可以實現一個簡單的通信框架,提供必要的功能,如果你需要的話。這和使用一些專門的MVC框架需要的成本是完全不同的。

然而,我的意見則是——MVC是非常好的架構模式,不管什麼樣的項目都建議嘗試使用,但是用框架的話,請務必謹慎。

關於最簡的MVC,最近看到一個讓人很囧的例子。不過這個例子對大家理解MVC是有幫助的。

這玩意的確……基本算是MVC,只差一點而已。MVC是架構模式,至少結構上要分開,即使不分文件至少要讓能看得出來誰是誰(原文可沒有紅字),所以只需要把這些代碼分成三個文件,那就可以稱得上是最簡的MVC了。

這是我在他的下面補充的代碼。

結果是,View只關心與自己相關的Model和Command,Command只關心與自己相關的View和Model,Model誰都不關心, 這和一般情況需要的解耦目標是一致的。雖然這樣並不算完全解耦,但是至少在思路和邏輯分離上是做到了,僅僅是協作方面存在問題,比如無法實現自由的並行開 發,而這個加入簡單的反射也可以解決。

所以,單純的MVC並不困難,沒什麼要不要放棄一說。還有就是上面只是極端例子,但就算是這種東西,比起完全不實現MVC,也至少實現了50%以上的內容。

是否使用框架應當理性對待

程序員都是理科生,應當用理科生的思考方式(當然我並沒有讓你們都去模仿Sheldon)。在使用MVC框架的過程中,不管是覺得好,還是差,都要考慮清楚問題的源頭在哪。

覺得MVC框架不好用,降低效率,是否曾經有過平行對比的例子,你能否確認不用它效率就確實能提高?效率低有沒有可能是框架之外的原因?

覺得MVC框架好用,提高效率,是否有平行對比的例子?你怎麼就知道是使用了框架的功勞,而不是規範了代碼結構,制定了新的協作流程,甚至是開發人員水平提高的功勞?怎麼知道MVC框架並沒有起了反效果?

使用了框架,看到了結果,然後根據結果的好話直接判定框架的好壞,這太武斷了,作爲一個理科生,我們絕對不能這樣做。至於那類連比較都沒有,而是以“我用了框架,項目依然完成了,沒有因爲用了框架而失敗”這種理由來支持使用某個框架的人,我無言以對。

推薦MVC框架

我並沒有完全反對使用MVC框架。這要看你的項目類型,規模,人數。滿足條件的時候當然可以使用。尤其是在企業應用裏,如果你有幸出現六個客戶端的話,沒MVC框架可能還真是會出問題。

pureMVC和Cairngorm 是兩個較早出現的框架,目前我不建議再使用它們。pureMVC的問題在於過於強調分離而缺乏實際功能,提供的便利很難抵消它本身的消耗,性價比較低。Cairngorm 的問題則在於過於強調模型更新視圖的流程,限制太多,靈活程度不夠。

後出的幾個框架就好多了,Mate使用了一個全局事件定義,配合FLEX寫法非常簡略。Swiz則是用控制反轉+依賴注入,也就是Spring的做法,而且元標籤注入的方式很有趣,感興趣的可自行查閱資料。

我這裏要說的是Robotlegs。這是一個和Swiz非常相似的框架,但也有一些自己的特點。首先它是基於pureMVC的,你依然可以像 pureMVC這樣來使用它,對於相信pureMVC的團隊它是很容易接受的代替品。他讓pureMVC也同樣擁有了控制反轉和依賴注入,包裝了大部分功 能,配置代碼大大減少,而且不管用不用FLEX framework都可以很自然地使用它。

Robotlegs的教程可以看這裏:

http://wenku.baidu.com/view/42a08b235901020207409c60.html

但我得提醒大家,雖然我覺得Robotlegs很便利以及有趣,但是並沒有在項目裏使用它,因爲我的項目規模不大,而且是遊戲。實際上,我甚至自己 實現了一個依賴注入框架,可以很簡單的加入到現在的項目中,成本幾乎爲零,卻依然沒有去用。使用一個東西要看是否需要去用,而不是可以用就用,更不是“因 爲用了沒有遇到問題所以就用”。用一個東西必須有收益纔可以,尤其是在明明看到有損失的時候。僅僅是用“看起來更正規”這類自我滿足的理由來決定自己的行 爲,太愚蠢了。

當然,如果你需要它,那就應該毫不猶豫的使用。不要受到抱怨框架的人影響,他們大部分都有自己的問題,提出的理由也未必是正確的,你並不一定會赴他們後塵——前提是你真的需要它,而且,要將使用框架需要的條件全部補齊。

就算是使用MVC框架也不需要完全解耦

解耦是一個擴展性要求,但擴展性要求並不是越多越好的。

這是一個普遍的誤區。諸如使用pureMVC的人,很多都糾結於完全的解耦,以至於用了Command,在Command中改變View的時候還是必須要發一遍Notification。

Command這種類,一般都是在相關的View,Model完成後纔開始編寫的。比如普通的 StartupCommand,OpenWindowCommand,沒有對象又如何編寫?它在編寫順序上應該是,就算不是也是可以放在View和 Model之後的。那麼在協作關係上,他就可以直接訪問所有相關類,不需要爲了這種原因而解耦。

雖然pureMVC將消息全局化了,但是消息實際上是分局部和全局的。比如一個Proxy發生變化要求所有監聽某個消息的View更新,那麼當然應 該發一個叫做I_AM_CHANGED的Notification,並由不同的View來監聽這個消息並更新,這個就應該是全局消息。但有些消息就是局部 的,是一對一的,比如一個叫做SEND_DATA_TO_WINDOW1的消息,按它的字面意思就應該是刷新WINDOW1,那麼由它來觸發的 Command,就應該直接耦合 WINDOW1這個View來設置值,而不是再發個類似REFRESH_WINDOW1的消息,因爲SEND_DATA_TO_WINDOW1的名字已經 確定是針對這個View了,如果最終它卻沒有操作這個View,那纔是有問題的吧?

解耦歸解藕,但是對於已經有了意義上的聯繫的模塊,結果卻不耦合,在任何時候都是沒有意義的。即使需求變化,邏輯變化了,使得 SEND_DATA_TO_WINDOW1最終不是改變WINDOW1的數據,而是WINDOW2的數據,那麼這個Command連帶相關 Notification的名字就必須修改,也就是說,意義上的緊密聯繫,在實際操作上和耦合了是一回事。既然已經是這樣了,再做成不耦合,給自己製造麻 煩的又有什麼意義呢?

除了上面的情況,我們也要考慮,真的有必要將項目拆得那麼細緻麼,有沒有必要爲了1%以下的可能性來解耦兩個相關性很強的部分?比如一個叫做 ShopPanel的View和一個叫做ShopModel的Model,到底在什麼情況下,ShopPanel會不去調用ShopModel,而是別的 東西?而且Panel上可能還有各種文字,使得自己意義上只能調用商店的數據。真是要調別的東西,應該重新制作一個新的View吧?而且別忘了 pureMVC是可以多個Mediator套用一個View的。這種情況下,我們直接在Mediator中耦合ShopModel,有什麼不可以的?當 然,反過來,ShopModel被多個View調用的情況很普遍,所以我們不能讓它來耦合ShopPanel。這些規則實際上是很明確的,是完全可以預知 的。就算預知錯誤,也是很容易修正的。

解耦是手段,而不是目的。盲目的最求擴展性,只會讓自己的程序變成一盤散沙。正是適量的耦合,程序才能擁有一個確定的形態,纔不會讓人感到茫然。

普遍誤解

其實現在使用框架的人羣裏,真的能夠發揮框架長處的確實比較少,尤其是在水平層次較低的Action Script開發人員之中。一方面,這污染了框架的名聲,同時也是不建議使用框架的理由之一,因爲人員水平限制也是實際項目中不可迴避的現實問題。

如果你決定使用MVC框架,就必須提高自己的認識。我揀幾個最常見的問題來說吧。

  • 並不是用了消息通信就算用了MVC

消息通信只是一個手段,只使用框架的通信功能在View之間發送消息的話,而將其他功能全部拋棄的話,直接使用事件更好,那還套一個MVC框架就是在沒事找事了。

MVC關鍵還是在於代碼邏輯的分配,通信只是個附贈品而已。要了附贈品而扔了原來的商品——咱們買的不是小浣熊乾脆面,對吧。

但是如果你的目的就是贈品,其實也沒什麼。比如你就是想用的這個通信框架來發發消息,就不打算用它的MVC,又或者MVC部分是自己實現的。那麼我還是建議你把消息部分乾脆也自己實現了,別人的始終沒有自己的好。

既然用了MVC框架,就不要圖省事

要清楚,鬆散耦合不僅僅是一個形式,目的在於減少模塊間的聯繫。因此,如果你一方面在解除兩個模塊之間的耦合,一方面自己又沒頭沒腦的將其他模塊的內容耦合進來,就會使得你的行爲變得沒有意義。

現在一些人一方面在硬套框架,一方面又圖省事而隨意引入其他類,就屬於這樣的行爲。那些類是可以引入,但你這樣做,框架本身的意義就沒有了。要不你就不用框架,要不就別這樣幹,這裏只能二選一。

是Mediator知道View的一切,View完全不知道Mediator,而不是相反

對於使用pureMVC的同僚們,我真是不明白你們到底是怎麼把這個反過來理解成“View知道Mediator的一切,而 Mediator完全不知道View”的,因爲官方實例上寫的很明白。估計是把mediator當成通信專用的模塊類了吧。但是如果你放棄了 mediator分離View代碼的特性,只是用來通信的話,至少要保留原來的通信功能,就是讓Mediator依然可以直接訪問View。否則既然 Mediator是用來通信的,它卻不能操作View,結果還得設法和View再通信一次……

pureMVC要求“View完全不知道Mediator”是爲了能夠在不修改View的情況下更換Mediator,但這種需求並不多 (多的是在Mediator不變的情況更換View,這個需要用接口或者條件判斷解決),所以可以放寬點讓他們互相引用,這樣兩者通信都能暢通。

pureMVC實現“View完全不知道Mediator”的方法是用Mediator直接去監聽View的某個組件的鼠標事件。這隻需要監聽一次,也不需要傳遞消息。Mediator存在的期間,按pureMVC的標準View應該是沒有任何監聽邏輯的。

擴展閱讀

http://baike.baidu.com/view/31.htm

http://www.360doc.com/content/09/0804/08/163747_4655702.shtml

http://hi.baidu.com/5%B1%CF%D2%B5%D2%D4%BA%F3/blog/item/2a018366a08e54cde6113af7.html

http://hi.baidu.com/lwcandwo/blog/item/8fb4b3036d01eb8ad43f7cf4.html

http://developer.51cto.com/art/200904/120649.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章