#MVP的两种实现方式
MVP有两种变体:Passive View和Supervising Controller。两者的主要区别就是View和Model是否直接交流。
#被动视图(Passive View)
View和Model不知道彼此。Model的变化要告知Presenter,再由Presenter来改变View。
优点是View和Model解耦了。缺点是Presenter会比较重,数据更新需要手动完成,这就意味着放弃了数据绑定功能。

#监督控制器(Supervising Controller)
View可以知道Model的存在。让Model通过事件等方式发出数据变化的通知,View订阅Model的变化。
这主要是利用了语言或框架的特性让View直接感知Model的变化,而不用经过Presenter,这样可以减少代码量,缺点是View对Model耦合了。

#M、V、P之间的关系
先看图

为 V 定义一个接口,接口中暴露的方法就是为 P 提供的。这么做的目的是为了让 P 不知道 V 的存在,从而让 P 仅依赖接口,这样更容易测试 P。
V 和 P 是 1:1 的关系。
P 和 M 是 1:N 的关系。
#让 View 独立
先看一个典型的View和Presenter连接的地方
1 | public class Presenter |
当用户触发一个 UI 行为,比如点击鼠标时,如何让Presenter响应呢?基本上就两种方式:
- 让
View直接调用Presenter中的方法。但这会产生耦合。 View利用事件等机制实现广播,让Presenter去订阅View产生的通知。这样View就是完全独立的。但需要在释放时取消订阅事件,这比直接调用Presenter的方法多了一些步骤。
普遍共识是采用第二种方式,让View不知道Presenter的存在。但这只是理想情况,现实开发中还有很多复杂性,所以还是得看情况决定用哪种方式。
但是上面的例子View依然还是知道如何创建Presenter:
1 | public class View : IView |
此时你有三种选择:
- 在类的外部将
View和Presenter连接起来(订阅通知)。 - 创建一个
PresenterFactory工厂类,构造过程交给它。
1 | mPresenter = PresenterFactory.Create<MyPresenter>(); |
- 使用 IoC 容器注入(推荐)。
1 | public interface IHomeView { } |
至此,View仅仅只是知道一个什么都没用的IPresenter接口,从来不会使用它,持有它只是为了保持Presenter的生命周期。
最后记住在View关闭时通知Presenter互相解除引用。
#参考
浅谈 MVC、MVP 和 MVVM 架构模式
MVP 和 MVC 是什么以及有什么区别?
如何在 WinForms 中使用 MVP 的依赖注入?