當(dāng)我們談?wù)揗VP的時(shí)候,我們?cè)谡f些什么-14條軍規(guī)

下面我簡單翻譯的關(guān)于MVP設(shè)計(jì)模式中的14條準(zhǔn)則:

  1. 所有的View都應(yīng)該以View后綴結(jié)束:TaskView/ITaskView
  2. 所有的Presenter都應(yīng)該以Presenter后綴結(jié)束:TaskViewPresenter
  3. 讓Presenter來處理所有請(qǐng)求,View僅處理GUI的操控細(xì)節(jié)。換句話說,就是View不處理具體的業(yè)務(wù),應(yīng)該交由Presenter來處理,View僅僅響應(yīng)用戶操作,以及完成數(shù)據(jù)綁定。
  4. View對(duì)Presenter方法的調(diào)用應(yīng)該像事件觸發(fā)一樣:OnXxx()
  5. View對(duì)Presenter的調(diào)用應(yīng)該盡量少,而且只能是第4點(diǎn)的調(diào)用方式
  6. 禁止通過Presenter直接訪問Model或者Service取得結(jié)果,Presenter的方法都應(yīng)該是無返回值的。這樣可以保證View不是從Presenter拉去數(shù)據(jù),而是有Presenter主動(dòng)將結(jié)果推送給View。
  7. Presenter對(duì)View的調(diào)用,應(yīng)該僅通過接口。每個(gè)View都應(yīng)該對(duì)應(yīng)一個(gè)IView, Presenter只依賴IView,不依賴實(shí)現(xiàn)。這樣可以在單元測(cè)試的時(shí)候Mock View。
  8. View中除了IView中定義的方法之外都應(yīng)該是非Public的。
  9. 除了Presenter,禁止從其他的地方直接訪問View。
  10. IView中定義的方法應(yīng)該根據(jù)use-case取一個(gè)具有業(yè)務(wù)含義的名稱,像SetDataSource這樣意義模糊的命名是不合適的。
  11. IView中不要只定義方法,不應(yīng)該定義屬性。Presenter對(duì)View調(diào)用應(yīng)該通過方法的調(diào)用,而不是Set Data。
  12. 數(shù)據(jù)應(yīng)該保持在Model中。
  13. View中方法名不應(yīng)該包含具體的控件名,這會(huì)導(dǎo)致Presenter知道太多的View的實(shí)現(xiàn)細(xì)節(jié)。
  14. View中的方法名應(yīng)該具有業(yè)務(wù)含義,這樣代碼更容易被理解和自描述。

個(gè)人觀點(diǎn)

  • 第4、5點(diǎn)說的是View怎么調(diào)用Presenter的方法,目的是View傳遞用戶的請(qǐng)求給Presenter。個(gè)人的觀點(diǎn)更為激進(jìn), 我覺得應(yīng)該杜絕View對(duì)Presenter方法的調(diào)用。
    那么,View應(yīng)該如何調(diào)用Presenter呢?沒錯(cuò),event。View一定是被用戶觸發(fā)了某個(gè)事件,才需要請(qǐng)求Presenter的,同時(shí)這個(gè)事件就是某一個(gè)業(yè)務(wù)。那么我們應(yīng)該在IView中定義好相應(yīng)的event,然后在Presenter中訂閱相關(guān)的事件即可。
  • 第11點(diǎn), 個(gè)人覺得在IView定義屬性也未嘗不可。Presenter往View推消息當(dāng)然是用方法更有語義。但是有的時(shí)候,Presenter收到某些來自View的請(qǐng)求的時(shí)候,我們同時(shí)也需要一些View上其他Data。
    也就是說,有的時(shí)候我們同時(shí)要對(duì)View獲取或推送Data,那是不是可以考慮直接定義成屬性呢? 當(dāng)然這是一種方式。
    如果嚴(yán)格執(zhí)行第11點(diǎn)的建議,我們也可以用參數(shù)將Presenter需要的數(shù)據(jù)傳遞給Presenter。具體來說就是將就是通過event的EventArgs來傳遞,這是另一種方式。

原文:Design Rules for Model-View-Presenter
In my current project the MVP pattern is used in the supervising controller mode. The MVP pattern is an adaption of the old MVC pattern that incorporates that the capabilities of WinForms views have become smart enough to lift some of the burdens previously implemented in the controller. This applies to e.g. handling click events and data-binding; a presenter only injects the model into the view which exploits data-binding, while a controller explicitly sets the values of each control in the view. In short, a presenter should handle the use-case logic only, not the view logic.
Each view must implement an interface that defines all interactions that the presenter has with the view. This ensures a clear separation between the presenter and the view, and has the advantage of making the presenter easy to unit-test using mocking. The view never calls other modules and services directly; it must always use an event to request that the presenter provides the needed data or service.
This project uses CAB/SCSF to generate the view modules. The generated code is not quite as I would like it, I prefer that the view has no knowledge of the presenter and no direct access to it either as this gives a cleaner separation between views and presenters. I prefer that the view interface defines a set of events that is used to communicate view events to the presenter. This makes it harder for unknowledgable programmers and code monkeys to misuse the presenter reference; making shortcuts and ignoring the reasons for using patterns is very common and leads to unmaintainable code. Read Jeremy Miller's View to Presenter Communication for further opinions on this topic.
The following MVP design rules have a CAB flair, but are generally applicable to any MVP implementation:

  1. All views should have a XxxView suffix: TaskView/ITaskView
  2. All presenters should have a XxxPresenter suffix: TaskViewPresenter
  3. Let the presenter do all use-case processing, but keep GUI control details in the view
  4. All presenter methods called by the view must start with OnXxx() as they are events by design (MVP)
  5. Calls from the view to the presenter should be kept at an absolute minimum, and used for "event" type calls only: _presenter.OnViewReady();
  6. It is FORBIDDEN to use the presenter reference to access the model or services directly, no return values from presenter methods
  7. Calls from the presenter to the view MUST go via the interface only
  8. No methods in the view shall be public unless they are defined in the interface
  9. It is FORBIDDEN to access the view from anywhere but the presenter, except for loading and showing the view from the CAB ModuleController
  10. The interface methods shall have long meaningful names (not "SetDataSource") based on the domain language of the use-case
  11. The interface should contain methods only, no properties - afterall the presenter drives the use-case by calling methods, not by setting data
  12. All data in the MVP component should be kept in the model, no data should exist only as properties of UI controls
  13. The methods of the view interface should not contain UI control name references (e.g. AddExplorerBarGroup) as this makes the presenter know too much about the implementation technology of the view
  14. Stick with domain naming in the view methods (e.g. AddTaskGroupHeader), this makes the code easier to understand and the tests self-describing
    Rule 11 and 12 might surprise you if your perception of the model is that it contains business entities only - traditional database-driven design thinking. The model is rather business process documents that are involved in the use-case, i.e. domain entity and value objects. Even views used for searching have a model, it is a specification or query object. Jeremy has some guidelines on assigning responsibilities in MVP.
    Rule 6 helps adhering to the "tell, don't ask" principle - properties make it far too easy to ask, rather use methods on the view to tell it what to do. I've seen design-time view data-binding directly against presenter properties, not exactly separation of concerns. Neither is it very testable, as there is no interaction from the presenter through the view's interface when the view asks the presenter directly. When mocking the view, there will be no recorded / testable interaction.
    Using long meaningful names in the view interface has the nice side-effect of making the presenter unit-tests a kind of mini documentation.
    I wish there was a FxCop Contrib project on CodePlex like for EntLib, CAB/SCSF and ASP.NET MVC. Then maybe I would write and publish some of these MVP design rules as custom FxCop rules.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 內(nèi)容作為新媒體運(yùn)營非常重要的一部分,讓很多人惱得恨不得擼光了頭發(fā)。做原創(chuàng)?都說原創(chuàng)才是最棒噠,容易形成差異化,那么...
    文中老濕閱讀 1,702評(píng)論 0 1
  • 在昌平路上的“小說咖啡館”,看了一部1983年的法國電影《關(guān)于我們的愛情》,導(dǎo)演是莫里斯·皮亞拉。這部電影真“法國...
    萌之刺刺閱讀 6,584評(píng)論 0 2
  • 有些問題是需要語言來解決的,有些問題是需要暴力來解決的,有些問題可以通過和平的方式來解決,有些問題必須用武力才能見...
    李一十八閱讀 383評(píng)論 0 0
  • 遇見是兩個(gè)人的事,離開卻是一個(gè)人的決定,遇見是一個(gè)開始,離開卻是為了遇見下一個(gè)離開。這是一個(gè)流行離開的世界,但是我...
    大寶媽咪娜娜閱讀 463評(píng)論 0 1

友情鏈接更多精彩內(nèi)容