"設計模式"這樣的話題彷佛快被園子裏的兄弟們寫透了, 從簡單的工廠到 MVC, MVP. 而關於MVVM彷佛談論得相對少些, 今天簡單地說說. 值得聲明的是: 這裏僅僅談論得是本身對別人發明的東西的一些理解, 可能有所偏誤, 望理解. 另外, 搜索了一下,園子裏 "clingingboy" 和 "高陽"大哥也談到了這個模式, 你們不妨參考一下.
在閱讀如下內容之前,建議你對這些內容有所瞭解: WPF, MVC, MVP, MVVM. 關於MVVM語法層面的內容請參考這裏: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
1, 前提
能夠說MVVM是專爲WPF打造的模式, 也能夠說MVVM僅僅是MVC的一個變種, 但不管如何, 就實踐而言, 若是你或你的團隊沒有使用"Binding"的習慣, 那麼研究MVVM就沒有多大意義.
另外,我的以爲, 使用Command以及打造一種合理的簡化的方式去使用Command也與使用Binding同樣重要.
2, 誕生
爲了解決現實世界中的問題,咱們須要將現實世界中的事物加以抽象, 而後獲得了Domain Object, 不管貧血的仍是富血的, 咱們均可以簡單地把他們歸結爲"由現實世界抽象出來的模型", 也就是咱們的model, 也就M-V-VM中的"M".
但其沒法與咱們的用戶進行交互, 因此, 咱們須要爲其建立一個界面(視圖, View), 該視圖能夠與用戶輸入設備進行交互, 這很棒, 但問題是如何將View與咱們的model關聯起來? Binding即可以發揮做用了, 好比視圖上的某一個文本框中的文本和Model中的"用戶名"關聯起來, 用戶即可以經過操做該文本框來訪問和修改Model的"用戶名"了.
這是極其簡單的狀況, 但實際編程時咱們發現, Model中的屬性(與方法)每每不那麼容易與View中的界面控件關聯起來, 好比, "類型不匹配": 界面控件所須要的類型與模型中屬性提升的類型不匹配. "須要額外操做": 模型中的數據須要通過一些額外的處理才能傳給視圖,反之亦然. 此時, 咱們意識到View彷佛須要一個"Helper"類來處理一些額外工做.
這個helper所包含的代碼能夠放在除了Model外的不少地方(咱們如今不考慮貧血富血之類的爭論), 好比View中, 記得本身剛學習窗體程序開發時就是這麼幹的, 將絕大多數處理邏輯放在那個所謂的CodeBehind中. 後來,正如你們在各類設計模式書籍中所看到的同樣,爲了將View和Model剝離開來,實現view可替換(好比你能夠講本身精心設計的軟件同時運行於窗體程序,Web甚至Mobile上), 便有了MVC. 有了MVC之後彷佛就開始滋生M-V-XXX之類的爭論與變種模型, 好比MVP以及這裏的MVVM,甚至MVP也有着Supervising Controller與Presentation Model兩種方式. 但主要圍繞兩個問題,一是model與view之間的關係, 徹底隔離的?單向的仍是雙向的? 二是這個"XXX"須要完成哪些功能,簡單流程調度?複雜規則處理? OK,這些爭論都沒有關係, 是否採用某種模式取決於你的開發所處的環境(好比語言特性,框架特性)以及你的業務特性以及所面臨的主要變化點等等.
但與MVC,MVP所不一樣的是,MVVM的引入不只僅是技術上的緣由(解除耦合應對變化等老生常談),另一個很大緣由是:軟件團隊開發方式的改變.若是你作過一段時間的WPF項目開發的話,你可能會有比較明顯的感受:在View層打造上,如何分配程序員和美工的工做.在繼續閱讀以前,你們能夠看看我之前的一篇文章"在UI Designer與Developer之間". 之前咱們團隊採用的即是"集成模式", 我便兼職了其中的"Integrator"角色.這還不錯.但說實在的,這僅僅是一個在特殊狀況下不得已而爲之的暫時方案,因此咱們付出了很大的努力開始轉向"收割模式"了,要轉向這個模式,至少須要兩個基本條件:
(1)你擁有可以熟練運用Blend等工具能爲程序員輸出XAML的美工, 他專一於純粹的UI/UE, 另外他還必須具備必定的"程序員"思惟.以便輸出的東西能很好地做爲程序的一部分而運轉起來,而不是僅僅"看上去"是那樣的.
(2)你須要可以脫離View層但仍能編寫出高質量代碼的程序員.
幸運的是, 咱們在努力創造條件1,並取得了很好的效果.(你能夠招一個具備Flash腳本編寫經驗的而且有極大的學習熱情的美工人員, 並對他進行Blend的相關培訓). 而MVVM模式爲咱們實現第二個條件提供了極大的便利. 爲何MVC/MVP模式不行而MVVM能夠呢? 很簡單, 在MVC和MVP模式中, View層都具備不少代碼邏輯, 開發View層的是程序員, 雖然UI/UE團隊會作不少工做, 但這個層的"實現者"仍然是程序員. 在之前的開發中,其工做得很好, 而在WPF開發中程序員對View層的展示顯得力不從心了,美工(指符合上面條件1的美工)雖然很擅長, 但他會說"惋惜我不會程序".因而, 咱們須要一種方式將View層的代碼邏輯抽取出來,並View層很純粹以便徹底讓美工去打造它.相應地, 須要將View層的相應邏輯抽取到一個代碼層上,以便讓程序員專一在這裏.
回想一下, 咱們只因此要在View(Xaml)背後寫一些代碼(C#), 無非是想傳遞一些數據以及傳遞數據時的數據的處理或在用戶與界面控件進行交互時執行一些操做, 最簡單的例子是在MVC中當界面發生交互時View去調用Controler中的某個方法, 以便將該操做的相應"指示"傳遞到"後臺"去. 在之前的技術中, 這樣的"銜接性"的代碼是必須的. 而在WPF中, 則能夠經過另外的技術來進行層與層之間的"銜接", 這就是"Binding" 和"Command", 以及稍後咱們會提到的"AttachBehavior". 經過Binding, 咱們能夠實現數據的傳遞; 經過Command, 咱們能夠實現操做的調用.(AttachBehavior的做用稍後再談). Binding和Command是能夠寫在XAML中的, 這樣看來XAML後面對於的CS文件能夠被徹底拋棄或不予理會了. 這樣的XAML文件正是美工所須要的. 而這些對於Binding以及Command的定義描述以及其餘相關信息的代碼應該放在那裏呢, 固然不是View, 更不是Model, 是"ViewModel". ViewModel是爲這個View所量身定製的, 它包含了Binding是所需的相關信息,好比Converter以及爲View的Binding提供DataContext, 它包含了Command的定義以便View層能夠直接使用, 另外,它仍是一個變種的Controler, 它得負責業務流程的調度.
因而, 便有了這副圖, 而後, 正如"時勢造英雄"所言, MVVM就誕生了.
3, ViewModel 與 單元測試
若是你是一名正在使用MVVM模式打造軟件的程序員, 那麼我勸你儘快忘掉View. 你所面對的是這樣一個模式"UnitTest-ViewModel-Model"(這並不是一個模式, 僅僅是我爲闡述觀點而暫時如此表述的).
記得曾經有一個Model-View-AbstractView模式, 而MVVM中的VM實際也是一個AbstractView: the abstraction of view. 它是一個抽象的View, 具備一個View的靈魂,而不具有相應的可視化控件而已. 因此對於程序員而已, 打造這樣一個抽象的VM就能夠認爲是完成View層的打造了.而當美工完成無數控件組成的實際的View後, 咱們就能夠用Binding和Command這樣的黏合劑將這個抽象的View和實際的View黏合在一塊兒了.
那麼在黏合以前, 咱們怎麼知道本身的VM是否正常工做呢? 單元測試!
在說明對於ViewModel進行單元測試的重要性以前, 送給你們一句話: "View and Unit Test are just two different types of ViewModel consumers" (Josh Smith). 若是咱們將ViewModel看做生產者, 那麼View和Unit Test都是具備同等地位的消費者而已. 而且UnitTest相比於View而言具有更大的消費能力. 或者你能夠簡單的認爲View也僅僅是一種不太推薦的測試方式而已. 因此要實施好這個模式, 那麼對ViewModel的單元測試就是必須的了,而且這個測試要不依賴於任何UI控件. (那麼不是不對應ViewModel的開發是否是就應該經過測試來驅動了?TDD?)
4, AttachBehavior
通常狀況下利用Command, Binding, AttachProperty等WPF特性, View和ViewModel之間能配合工做得很好. 假設咱們有一個Button, 當該Button被點擊的時候咱們要完成一些操做, 很簡單, 將該操做封裝成一個Command並綁定到該Button上就能夠了, 但若是咱們要在Button被Load的時候執行另一些操做呢? 因爲Button沒有直接被Load事件所觸發的Command, 因此不能使用Command了. 不能直接將Load事件處理器寫在Button所在的Xaml所對應的CS文件裏, 這和咱們剛纔對MVVM的設計是相矛盾的. 一個不太好的方案是繼承一下Button, 並撰寫一個由Load所觸發的Command, 這可行, 但明顯很差. 正如一個控件沒有某個屬性而且在不繼承的狀況下而採用AttachProperty同樣, 咱們能夠採用AttachBehavior. AttachBehavior不是WPF特性, 它僅僅是一個最佳實踐, 一個Pattern. 關於AttachBehavior語法如何書寫, 請參考 : http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx
html
http://www.cnblogs.com/zhouyinhui/archive/2009/07/23/1529524.html程序員