JavaShuo
欄目
標籤
應用MVP模式對遺留代碼進行重構
時間 2019-11-12
標籤
應用
mvp
模式
遺留
代碼
進行
简体版
原文
原文鏈接
AV(Autonomous View)自治視圖
在面向終端用戶的應用中,都須要一個可視化的UI來與用戶交互.這個UI稱爲View視圖.
在早期,咱們習慣將全部前臺的邏輯,與視圖揉在一塊兒,稱爲AV自治視圖.
這些邏輯包括:數據呈現(Display),用戶動做的撲捉與響應,數據存儲等.
在.Net的Winform和ASP.NET Web Form中,採用的都是事件驅動模型.
AV是將全部UI相關的邏輯都註冊到視圖自己,或者視圖元素對應的事件上.
人機交互應用的3個關注點.
數據在UI上的展現.
UI處理邏輯.
業務邏輯.
AV的缺陷
首先,業務邏輯與UI無關,因此應該最大程度地被重用.而在AV中,業務邏輯糅合在UI中,沒法重用.例如,從winform遷移到web form上.
穩定性:業務邏輯>UI處理邏輯>UI.
而3者糅合在一塊兒後,具備最弱穩定性的UI決定了總體的穩定性.
這屬於典型的"短板效應".
任何涉及到UI的組件都是不可測試性的(至少是很難測試).因此AV對測試不友好.
MVC模式
針對AV的缺陷,採用SOC(關注點分離)來剝離3個部分.
將人機交互應用分爲3個部分
Model:對應用狀態和業務功能的封裝.
維護着整個應用的狀態(數據和行爲),並實現了全部的業務邏輯,能夠看作爲一個領域模型.
View:實現可視化界面的呈現,捕捉最終用戶的交互操做(鍵盤,鼠標).
Controller.
View捕獲到用戶交互操做後會直接轉發給Controller,後者完成相應的UI邏輯。
若是須要涉及業務功能的調用,Controller會直接調用Model。
在完成UI處理以後,Controller會根據須要控制原View或者建立新的View對用戶交互操做予以響應.
View和Model存在直接的聯繫.
View能夠直接調用Model查詢其狀態信息。
當Model狀態發生改變的時候,它也能夠直接通知View.
Model對View的數據狀態改變通知,View對Controller的用戶交互通知.都是單向的消息交換.
可使用事件機制來實現這兩種通知.
也能夠經過觀察者模式經過註冊/訂閱的方式來實現.
View做爲Model的觀察者,經過註冊相應的事件來檢測數據狀態的改變.
Controller做爲View的觀察者,經過註冊相應的事件來處理用戶的交互操做.
MVP模式
MVC模式存在的問題
View和Model能夠繞過Controller來直接進行交互.
對於用戶驅動的程序(人機交互),咱們不須要Model來主動通知View數據狀態的變化.因此,Model應該是徹底獨立的.
MVP模式的目標
測試(Unit Test)友好.
關注點分離.
正交性.
每個操做都只改變一件事情,而沒有其它的反作用.
解依賴
對View和Model解耦.
下降了Presenter對View的依賴.從依賴於具體的View到依賴於抽象的IView接口.
交互
Presenter對Model的單向調用.
Presenter和View之間的雙向交互.這個是核心.
Presenter和View之間交互的方式
PV(Passive View)
爲了避免作對UI的測試(難到幾乎不能),應該在UI中不進行UI邏輯的處理.
一個被動的View.View中的UI元素(控件)不是由View自己操做,而是由Presenter控制對UI元素的操做.
須要將View中的元素以屬性或者其餘方式暴露,以供Presenter操做.
在數據綁定中,控件類型的選擇應該是View內部的邏輯,不該該出如今Presenter中.
因此,在IView的定義中,不能涉及到具體的控件類型.
而是返回一種數據綁定所需的數據類型.
而後在View內部處理數據到控件的綁定.
PV對測試友好,由於全部的UI處理邏輯都在Presenter中,便於測試.
缺陷
對於一個複雜的UI(含有不少元素),IView接口將會十分龐大.
Presenter須要對UI元素進行操做,因此要了解不少的UI細節.形成簡單事情複雜化.
Soc
將諸如格式化,數據綁定這些簡單的UI邏輯移到View中.在View中進行一些簡單的UI邏輯處理.
View自己僅實現單純獨立的UI邏輯,它處理的數據應該是Presenter推送給它的.
因此View儘量不維護數據狀態.在Iview接口的定義中不包含屬性.
Presenter所需的View狀態應該是View在請求交互處理時給它的.
第一次改造:最薄的View.
起源:因爲View持有對Presenter的引用,因此理論上,View是能夠無限制地調用Presenter的.
基於之前AV的編碼習慣,極可能形成如下的問題:
大部分(甚至全部)的UI處理邏輯都寫到View中.
而Presenter的做用就是Proxy,僅僅是調用View中的方法而已.
採用事件訂閱的方式來完成Presenter和View的交互.
首先,在IView中定義事件Handler.
爲了隔離事件參數中e的類型污染(一些控件的事件參數,會引入一些測試不友好的類型),定義一系列的事件參數類型.
而後,在View的控件事件處理函數中.
將處理事件須要的上下文信息,包裝到一個自定義的事件參數中,而後 Raise Event.
最後,在Presenter中,訂閱IView暴露的各類事件,並進行處理.處理時須要的上下文在自定義的事件參數中.
優缺點
View只完成了純粹的佈局展現.
在事件處理流程中,若是須要Cancel處理,會比較難作到.
第二次的改造
在View中調用Presenter的方法.完成部分的UI邏輯.
工程劃分(使用Company來替代真實信息).
Company.MVP.ICommonView.
包含了對使用到的控件的抽象View接口,在每一個接口中暴露出來Presenter須要使用到的屬性和函數.
每一種控件類型一個接口.
Company.MVP.ComonViews.
對於每個控件,實現一個繼承了IXXXView接口的類.
在這些類中,體現了具體控件的屬性和方法的細節.
Company.MVP.Common.
該工程含有3個子文件夾.
ModelObjects. Model的一部分,業務模型的抽象類.
Service. Model的另一部分,定義了數據訪問接口.
View:定義了UI頁面須要實現的接口.
Company.MVP.Presenter.
Presenter的具體實現.
Company.MVP.Service.
數據訪問接口的具體實現.
Company.Client.
具體的UI工程.會實現Common中View的UI頁面接口.
工程間依賴.
Prensenter僅僅依賴於ICommonView和Common.而跟具體的UI控件類型,具體的UI畫面無關.
因此,可使用一個Presenter來對應多個的View展現(Client).
單元測試
針對Presenter.
對於Service和View,因爲P中操做的是二者的接口.因此可使用Mock來模擬這兩個部分.
而Model是能夠簡單地New出來的,不須要進行Mock.
針對Model.
使用業務場景,進行測試.並且對其測試時,不須要進行Mock.
針對View.
能夠進行少許的測試.由於有IView接口,因此能夠Mock控件的屬性和行爲,來針對UI頁面進行測試.
更換控件類型
UI應用中,最常常遇到的情形.例如,如今要將界面上的一個TextBox控件替換爲EditText控件.
在UI實現的Client工程的具體頁面類上,將實例化之前的成員時使用的類型從TextBoxView修改成EditTextView便可.
其餘的類和工程不須要修改.
改動被限定在了特定的地方.避免了短板效應.
總結
關於代碼量
使用MVP模式後,代碼量是確定不會比原先的少的.
考慮到View的重用,以及子Presenter的重用.代碼量增長的也很少.
關於控件的View類型的接口抽象及實現.
對於控件的View的接口,能夠只針對一個頁面,也能夠在工程前期,定義好對一個控件所需的全部的操做.這樣就在全系統中使用一份View的接口.
View接口對外暴露的應該是操做,而不是以控件屬性/方法的視角看待.也就是說Prensenter須要對控件進行什麼類型的操做,就暴露一個這樣的操做出來.
關於控件差別性的問題.
系統中不一樣界面中,同一控件的操做接口多是不一樣的.
按照MVP的本意,是沒有View重用的概念的.
可是,咱們能夠將同一控件基本的公用行爲抽象爲一個接口,而後使用一個類來實現它.而後在有特殊操做接口的畫面中,再定義一個繼承自公用接口的接口,而後使用一個類繼承公用類,並實現該接口.
關於控件的事件鏈.
在現有的代碼中,有不少地方用到了事件鏈的連鎖效應.
我的認爲,這是一種不太好的編程方式.這樣控件之間相互的依賴關係變得如此的複雜.改動事件鏈上的任何一個控件的任何一個事件處理,都須要查看其連帶的連鎖反映.
在MVP中,咱們在處理一個控件的操做時,會把全部控件須要展現的內容一次性地處理好,而後一把交給View進行展現.而不是使用事件的連鎖效應.
這樣,就解除了控件之間在事件上的相互依賴關係.
關於單元測試.
對於業務系統的單元測試,純粹的代碼覆蓋率是沒有意義的.
須要關注的是測試的場景覆蓋率.
即便覆蓋百分百的代碼.可是漏測了一種Case,同樣會出現Bug.
因此,咱們須要有很清晰的業務邏輯說明,來指導咱們進行單元測試時的Case場景輸入.
事件處理流程三部曲
IView中定義Event.
Event ButtonClick.
View中觸發事件.
Private withevents _item as button
Public sub itemClick() handles _item.Click
RaiseEvent ButtonClick
Presenter中掛接並處理事件
AddHandler OKButton.ButtonClick , Addressof Save.
目標
一個(種)控件,對外提供統一的行爲接口.
行爲包括:屬性,方法,事件.
畫面類職責清晰.
僅包含了控件的集合.
沒有任何的邏輯處理代碼.
更換控件類型時,改動最小.
僅需更改畫面類中New控時使用的實際View類型.
業務代碼和控件邏輯的分離.
業務代碼放在Model中.
控件邏輯,封裝在View的實際實現類中.
Model是徹底獨立的,不依賴於任何模塊.
相關文章
1.
「遺留代碼是**!」
2.
MVP應用架構模式
3.
傳統企業遺留系統的重構及代碼優化
4.
重構遺留代碼(1):金牌大師
5.
【Android】【代碼架構】MVP架構研究(二):MVP模式簡介
6.
MVP模式應用
7.
使用webStorm進行代碼重構
8.
使用AndroidStudio進行代碼重構
9.
使用Intellij IDEA 進行代碼重構
10.
遺留系統重構的模式與原則
更多相關文章...
•
Eclipse 代碼模板
-
Eclipse 教程
•
Markdown 代碼
-
Markdown 教程
•
委託模式
•
IntelliJ IDEA代碼格式化設置
相關標籤/搜索
代碼重構
遺留
重構與模式
代理模式
結構模式
架構模式
代碼模板
代碼架構
零行代碼
三行代碼
Hibernate教程
Redis教程
MySQL教程
應用
代碼格式化
設計模式
0
分享到微博
分享到微信
分享到QQ
每日一句
每一个你不满意的现在,都有一个你没有努力的曾经。
最新文章
1.
JDK JRE JVM,JDK卸載與安裝
2.
Unity NavMeshComponents 學習小結
3.
Unity技術分享連載(64)|Shader Variant Collection|Material.SetPassFast
4.
爲什麼那麼多人用「ji32k7au4a83」作密碼?
5.
關於Vigenere爆0總結
6.
圖論算法之最小生成樹(Krim、Kruskal)
7.
最小生成樹 簡單入門
8.
POJ 3165 Traveling Trio 筆記
9.
你的快遞最遠去到哪裏呢
10.
雲徙探險中臺賽道:借道雲原生,尋找「最優路線」
本站公眾號
歡迎關注本站公眾號,獲取更多信息
相關文章
1.
「遺留代碼是**!」
2.
MVP應用架構模式
3.
傳統企業遺留系統的重構及代碼優化
4.
重構遺留代碼(1):金牌大師
5.
【Android】【代碼架構】MVP架構研究(二):MVP模式簡介
6.
MVP模式應用
7.
使用webStorm進行代碼重構
8.
使用AndroidStudio進行代碼重構
9.
使用Intellij IDEA 進行代碼重構
10.
遺留系統重構的模式與原則
>>更多相關文章<<