MVP()
PV模式将所有的UI处理逻辑全部定义在Presenter上意味着所有的UI处理逻辑都可以被测试所以从可测试性的角度来这是一种不错的选择但是它要求将View中可供操作的UI元素定义在对应的接口中对于一些复杂的富客户端(Rich Client)View来说接口成员将会变得很多这无疑会提升编程所需的代码量从另一方面来看由于Presenter需要在控件级别对View进行细粒度的控制这无疑会提供Presenter本身的复杂度往往会使原本简单的逻辑复杂化在这种情况下我们往往采用SC模式
在SC模式下为了降低Presenter的复杂度我们将诸如数据绑定和格式化这样简单的UI处理逻辑转移到View中这些处理逻辑会体现在View实现的接口中尽管View从Presenter中接管了部分UI处理逻辑但是Presenter依然是整个三角关系的驱动者View被动的地位依然没有改变对于用户作用在View上的交互操作View本身并不进行响应而是直接将交互请求转发给Presenter后者在独立完成相应的处理流程(可能涉及针对Model的调用)之后会驱动View或者创建新的View作为对用户交互操作的响应
View和Presenter交互的规则(针对SC模式)
View和Presenter之间的交互是整个MVP的核心能否正确地应用MVP模式来架构我们的应用主要取决于能否正确地处理View和Presenter两者之间的关系在由ModelView和Presenter组成的三角关系中核心不是View而是PresenterPresenter不是View调用Model的中介而是最终决定如何响应用户交互行为的决策者
打个比方View是Presenter委派到前端的客户代理而作为客户的自然就是最终的用户对于以鼠标/键盘操作体现的交互请求应该如何处理作为代理的View并没有决策权所以它会将请求汇报给委托人PresenterView向Presenter发送用户交互请求应该采用这样的口吻我现在将用户交互请求发送给你你看着办需要我的时候我会协助你而不应该是这样我现在处理用户交互请求了我知道该怎么办但是我需要你的支持因为实现业务逻辑的Model只信任你
对于Presenter处理用户交互请求的流程如果中间环节需要涉及到Model它会直接发起对Model的调用如果需要View的参与(比如需要将Model最新的状态反应在View上)Presenter会驱动View完成相应的工作
对于绑定到View上的数据不应该是View从Presenter上拉回来的应该是Presenter主动推给View的从消息流(或者消息交换模式)的角度来讲不论是View向Presenter完成针对用户交互请求的通知还是Presenter在进行交互请求处理过程中驱动View完成相应的UI操作都是单向(OneWay)的反应在应用编程接口的定义上就意味着不论是定义在Presenter中被View调用的方法还是定义在IView接口中被Presenter调用的方法最好都没有返回值如果不采用方法调用的形式我们也可以通过事件注册的方式实现View和Presenter的交互事件机制体现的消息流无疑是单向的
View本身仅仅实现单纯的独立的UI处理逻辑它处理的数据应该是Presenter实时推送给它的所以View尽可能不维护数据状态定义在IView的接口最好只包含方法而避免属性的定义Presenter所需的关于View的状态应该在接收到View发送的用户交互请求的时候一次得到而不需要通过View的属性去获取
实例演示SC模式的应用(S)
为了让读者对MVP模式尤其是该模式下的View和Presenter之间的交互方式有一个深刻的认识我们现在来做一个简单的实例演示本实例采用上面提及的关于员工查询的场景并且采用ASPNET Web Forms来建立这个简单的应用最终呈现出来的效果如图所示前面我们已经演示了采用PV模式下的IView应该如何定义现在我们来看看SC模式下的IView有何不同
先来看看表示员工信息的数据类型如何定义我们通过具有如下定义的数据类型Employee来表示一个员工简单起见我们仅仅定义了表示员工基本信息(ID姓名性别出生日期和部门)的个属性
public class Employee
{
public string Id { get; private set; }
public string Name { get; private set; }
public string Gender { get; private set; }
public DateTime BirthDate { get; private set; }
public string Department { get; private set; }
public Employee(string id string name string gender
DateTime birthDate string department)
{
thisId = id;
thisName = name;
thisGender = gender;
thisBirthDate = birthDate;
thisDepartment = department;
}
}
[] []