MVC是现今挺被推崇的一种架构模式,而MVP在MVC的基础对视图与模型上再解耦,使结构和各自的功能也有所改变。在去年鄙人也尝试了一下使用MVP做了一个小Demo,作为了MVC的一个变体,MVP还分了两种模式,这个之前是不了解的,直到看了蒋老师的著作才知道。

  在MVP里面重点还是看View与Presenter之间的交互,View可以直接去调用Presenter,但Presenter对View的调用不是直接去访问View的实例,而是通过由View去实现的一个IView接口。唉MVP中能看到的就是这种对象与对象之间的交互,在细化一点去看,处理UI的逻辑部分搁在View里面还是搁在Presenter里面。这就是PV(Passive View被动视图)模式和(Supervising Controller监督控制器)模式的区别了。那么先来对两种模式稍作介绍,然后再通过一个Demo再体验一下两种模式。

PV模式

  在PV模式中,视图上的所有View的数据(具体点来说可以是控件的属性)都会暴露出来,供Presenter来调用。View的任务就是简单地在需要的时候把数据呈现出来,或者把数据提供给Presenter。涉及到一些UI逻辑的,无论复杂与否都与View本身无关。UI逻辑是Presenter的任务,这种方式使得View以一种很轻量级的形式存在,UI逻辑放到了Presenter里面,这样的做法有一种好处,就是方便了对UI逻辑做测试。但不足之处往往在于为了让Presenter对View数据操作更粒度更细化,View会提供比较多的属性,这样会使得IView接口变得庞大起来。

SC模式

  在SC模式中鄙人感觉最为受到强调的就是数据流动的单向性。无论是Presenter把数据推送到View这个方向,还是View接收到界面操作然后提交到Presenter,都应该是要单向的。也就是说当Prensenter把消息推送到View之后,View不要再给Presenter反馈信息(返回值),View把界面操作的响应提交到Presenter之后也不需要Presenter回传点什么。

那么下面就看看实际的例子

这是一个简单的通讯录,点击左边联系人名单,在右边就会显示出联系人的姓名和电话

对于View的布局而言,两者都是一样的

设计界面 运行效果

还有另一个相同的就是模型Model,这里的模型只有两个属性,一个是姓名,另一个是电话号码,还提供了一个静态方法去创建一个联系人的列表,代码定义如下

  1. public class ContactModel
  2. {
  3. public string PersionName { get; set; }
  4.  
  5. public string PhoneNumber { get; set; }
  6.  
  7. public static List<ContactModel> GetContactModelLists()
  8. {
  9. List<ContactModel> result = new List<ContactModel>();
  10.  
  11. result.Add(new ContactModel() { PersionName="Tom",PhoneNumber= "" });
  12. result.Add(new ContactModel() { PersionName="HopeGi",PhoneNumber="" });
  13. result.Add(new ContactModel() { PersionName="Jack",PhoneNumber="" });
  14. result.Add(new ContactModel() { PersionName="Tim" });
  15.  
  16. return result;
  17. }
  18. }

两种模式的差别在于IView和Presenter

  PV模式的视图只在提供界面的状态的属性,故IView的接口都是定义属性的

  1. interface IContactView
  2. {
  3. IEnumerable<ContactModel> ListBoxDataSource { set; }
  4.  
  5. ContactModel SelectedContact { get; }
  6.  
  7. string DetailPersonName { set; }
  8.  
  9. string DetailPhoneNumber { set; }
  10.  
  11. event Action SelectedContactChanged;
  12. }

  实现IVew接口的Form只需要把传入的属性赋到相应的控件上或者从相应的控件上获取属性返回回去则可。

  1. public partial class Form1 : Form,IContactView
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. }
  7.  
  8. public event Action SelectedContactChanged;
  9.  
  10. public IEnumerable<ContactModel> ListBoxDataSource
  11. {
  12. set {
  13. this.lstBoxContact.DataSource = value;
  14. this.lstBoxContact.DisplayMember = "PersionName";
  15. }
  16. }
  17.  
  18. public ContactModel SelectedContact
  19. {
  20. get
  21. {
  22. return this.lstBoxContact.SelectedItem as ContactModel;
  23. }
  24. }
  25.  
  26. public string DetailPersonName
  27. {
  28. set { this.lbDetailPersonName.Text = value; }
  29. }
  30.  
  31. public string DetailPhoneNumber
  32. {
  33. set { this.lbDetailPhoneNumber.Text = value; }
  34. }
  35.  
  36. private void lstBoxContact_SelectedIndexChanged(object sender, EventArgs e)
  37. {
  38. if (SelectedContactChanged != null) SelectedContactChanged();
  39. }
  40. }

  在视图中属性的get/set操作只是简单的取值赋值,那么判断逻辑与控制控制就交给了Presenter去处理

  1. class ContactPresenter
  2. {
  3. IContactView view;
  4. ContactModel model;
  5.  
  6. public ContactPresenter(IContactView view)
  7. {
  8. this.view = view;
  9. view.SelectedContactChanged += new Action(view_SelectedContactChanged);
  10. }
  11.  
  12. void view_SelectedContactChanged()
  13. {
  14. ContactModel _model = view.SelectedContact;
  15. if (_model == null) return;
  16. view.DetailPersonName =string.IsNullOrEmpty(_model.PersionName)?"--": _model.PersionName;
  17. view.DetailPhoneNumber =string.IsNullOrEmpty(_model.PhoneNumber)?"--": _model.PhoneNumber;
  18. }
  19.  
  20. public void ShowView()
  21. {
  22. if (view != null && view is Form)
  23. {
  24. view.ListBoxDataSource = ContactModel.GetContactModelLists();
  25. (view as Form).ShowDialog();
  26. }
  27. }
  28. }

那么现在看看另一种的模式——SC模式

  主要还是要看IVew的定义,因为IVew能提供什么,Presenter就能调用什么,至于怎么调用那是其次。

  1. interface IContactView
  2. {
  3. void BindListBoxDataSource(IEnumerable<ContactModel> datas);
  4. void BindContactDetail(ContactModel modelDetail);
  5. event Action<ContactModel> SelectedContactChanged;
  6. }

  一看上去其实我觉得跟PV模式的接口没太大区别的,因为如果转到Java而言,属性的get/set操作也是通过方法来实现的,这样子只是更换了方法名而已,但是再细心对比一下可以发现有差别,set操作的确换成了用方法来实现而不是用属性,但是这些方法都没有返回值,方法中也没有get操作,因为一般Presenter如果要获取View的参数是,基本上是界面上有用户操作触发了事件,这样Presenter处理用户事件时所需要的数据都用事件参数一并传到Presenter里面,待到Presenter处理完毕后把需要数据展示到View中去。

  1. class ContactPresenter
  2. {
  3. IContactView view;
  4. ContactModel model;
  5.  
  6. public ContactPresenter(IContactView view)
  7. {
  8. this.view = view;
  9. this.view.SelectedContactChanged += new Action<ContactModel>(view_SelectedContactChanged);
  10. }
  11.  
  12. void view_SelectedContactChanged(ContactModel obj)
  13. {
  14. this.view.BindContactDetail(obj);
  15. }
  16.  
  17. public void ShowView()
  18. {
  19. if (view != null && view is Form)
  20. {
  21. this.view.BindListBoxDataSource(ContactModel.GetContactModelLists());
  22. (view as Form).ShowDialog();
  23. }
  24. }
  25. }

这里的Presenter比PV的要简单,因为有一部分代码转移到View中去了

  1. public partial class Form1 : Form,IContactView
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. }
  7.  
  8. private void lstBoxContact_SelectedIndexChanged(object sender, EventArgs e)
  9. {
  10. if (SelectedContactChanged != null) SelectedContactChanged(lstBoxContact.SelectedItem as ContactModel);
  11. }
  12.  
  13. public void BindListBoxDataSource(IEnumerable<ContactModel> datas)
  14. {
  15. if (datas == null) return;
  16. lstBoxContact.DataSource = datas;
  17. lstBoxContact.DisplayMember = "PersionName";
  18. }
  19.  
  20. public void BindContactDetail(ContactModel modelDetail)
  21. {
  22. if (modelDetail == null)
  23. {
  24. lbDetailPersonName.Text = "--";
  25. lbDetailPhoneNumber.Text = "--";
  26. }
  27. else if (string.IsNullOrEmpty(modelDetail.PersionName))
  28. lbDetailPersonName.Text = "--";
  29. else if (string.IsNullOrEmpty(modelDetail.PhoneNumber))
  30. lbDetailPhoneNumber.Text = "--";
  31. else
  32. {
  33. lbDetailPersonName.Text=modelDetail.PersionName;
  34. lbDetailPhoneNumber.Text = modelDetail.PhoneNumber;
  35. }
  36. }
  37.  
  38. public event Action<ContactModel> SelectedContactChanged;
  39. }

  上述两个例子也模仿了蒋老师书中的Demo,但个人觉得这两个例子也不完全是Model,大概是我用的Model和是把存储数据的Model和处理一些逻辑的Model揉在一起了,因为在ASP.NET MVC中的Model与存储数据用的实体类是有区别的。对SC与PV的理解仅参考了蒋老师书上的一点内容,网上内容不少,如果上面有什么说错的欢迎大家指正,如果大家有更多的参考资料也欢迎分享,谢谢!

MVP的PV模式与SC模式的更多相关文章

  1. MVP模式和MVVM模式

    MVP模式 模型-视图-表示器,也就是MVP模式.是mvc模式的一种衍生模式,专注于改进表示逻辑. 与MVC不同,来自view的调用将委托给presenter(表示器),表示器通过接口与view对话. ...

  2. js架构设计模式——你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解?

    你对MVC.MVP.MVVM 三种组合模式分别有什么样的理解? MVC(Model-View-Controller)MVP(Model-View-Presenter)MVVM(Model-View-V ...

  3. javascript面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)

    面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下来将为大家讲解在JS中面向对象的实现.   工厂 ...

  4. 如何让你的传输更安全——NIO模式和BIO模式实现SSL协议通信

    对于SSL/TLS协议,如果要每个开发者都自己去实现显然会带来不必要的麻烦,正是为了解决这个问题Java为广大开发者提供了Java安全套接字扩展--JSSE,它包含了实现Internet安全通信的一系 ...

  5. 工厂方法模式——创建型模式02

    1. 简单工厂模式     在介绍工厂方法模式之前,先介绍一下简单工厂模式.虽然简单工厂模式不属于GoF 23种设计模式,但通常将它作为学习其他工厂模式的入门,并且在实际开发中使用的也较为频繁. (1 ...

  6. WCF学习之旅—请求与答复模式和单向模式(十九)

    一.概述 WCF在通信过程中有三种模式:请求与答复.单向.双工通信.以下我们一一介绍. 二.请求与答复模式 客户端发送请求,然后一直等待服务端的响应(异步调用除外),期间处于假死状态,直到服务端有了答 ...

  7. Java 策略模式和状态模式

    本文是转载的,转载地址:大白话解释Strategy模式和State模式的区别 先上图: 本质上讲,策略模式和状态模式做得是同一件事:去耦合.怎么去耦合?就是把干什么(语境类)和怎么干(策略接口)分开, ...

  8. Spark运行模式与Standalone模式部署

    上节中简单的介绍了Spark的一些概念还有Spark生态圈的一些情况,这里主要是介绍Spark运行模式与Spark Standalone模式的部署: Spark运行模式 在Spark中存在着多种运行模 ...

  9. Doctype作用?严格模式与混杂模式如何区分?它们有何意义?

    怪异模式和严格模式(译注:一般称为标准模式:Standards Mode,下文中的严格模式都可以理解为标准模式)是浏览器解析CSS时的两种‘模式’.这篇文章将简单阐述这两种模式之间的差异. 译注:一个 ...

随机推荐

  1. 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)

    前情回顾:一篇短短的博客明显不能满足TCP和UDP这两个饥渴的汉子,而且还被应用协议占了一小半的篇幅.在昨天结束之后,相信大家都基本对TCP/IP协议栈的轮廓有一个大概的印象了,能够对整体有所把握. ...

  2. 一个线上运营着3000+人的游戏,因为我不小心一个DROP DATABASE,全没了。 怎么办??跟我HOLD住!!!

    前言 今天下午3点,我按照惯例,打开游戏服务器,开新服部署嘛,游戏在腾讯开放平台,简单.闭着眼睛都OK.于是一轮子的复制黏贴拷贝,把服务器加起来,然后启动查看日志. ....突然发现不断的有Excep ...

  3. SWF READER 破解日志。

    网上传闻swf reader是破解最厉害的神器,可以内存抓取+doSWF反编译.所以去官网下了一个: SWF_Reader_2.3 不出所料,demo版本没有反编译的功能.网上搜到一个哥们尝试了下: ...

  4. 移动 Web 触摸与运动解决方案 AlloyTouch 开源啦

    传送门 Github地址:https://github.com/AlloyTeam/AlloyTouch 简介 AlloyTouch的本质是运动一个数字,把数字的物理变化映射到你想映射的任何属性上.所 ...

  5. 爱上MVC3~布局页的继承与扩展

    回到 目录 在MVC3中引入了Razor引擎,这对于代码的表现力上是个突破,同时母板页也变成了_Layout,所以,我们就习惯上称它为布局页面,在razor里,布局页面是可以继承的,即,一个上下公用的 ...

  6. EF架构~豁出去了,为了IOC,为了扩展,改变以前的IRepository接口

    回到目录 使用了4年的IRepository数据仓储接口,今天要改变了,对于这个数据仓储操作接口,它提倡的是简洁,单纯,就是对数据上下文的操作,而直正的数据上下文本身我们却把它忽略了,在我的IRepo ...

  7. struts2学习笔记之八:Action中方法的动态调用

    方法一:action名称+!+方法名称+后缀 Action类中增加addUser()和delUser()方法, package com.djoker.struts2; import org.apach ...

  8. FreeMarker 学习

    一.FreeMarker FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页.电子邮件.配置文件.源代码等)的通用工具. 它不是面向最终用户的,而是 ...

  9. Yii2框架RESTful API教程(一) - 快速入门

    前不久做一个项目,是用Yii2框架写一套RESTful风格的API,就去查了下<Yii 2.0 权威指南 >,发现上面写得比较简略.所以就在这里写一篇教程贴,希望帮助刚接触Yii2框架RE ...

  10. 队列-java代码

    public class QueueDemo { private int maxSize; private long[] queueArray; // 队列的头,实际是数组的尾 private int ...