三者之间的关系

在MVP初探里简单的描述了V和P之间是如何交互的。

无论是PV还是SC,M\V\P这三者之间的关系并没有发生改变,V只是前端的客户代理承现展显数据,P是如何处理客户交互行为的决策者。

数据是P主动“推”给V的,而V只向P发送用户通知,都是单向的;所以在IView中被Presenter调用的方法应该都是没有返回值的。可以通过调用IView中的方法,也可以通过事件注册的方式来实现P/V之间的交互。

那么,在PV模式下View是被动的,而P则控制着对V请求的处理;view仅将用户的(事件)请求提交到P,它并不参与对用户请求的处理,如果在这个过程中P要V参与(如:显示实时的数据等)也是P将要展现的数据PUSH到V,对于处理的结果的呈现也是同样的处理方式。

而P在此过程中的角色是一个决策者,它决定如何处理V提交过来的用户请求,如何去实现业务逻辑和调用Model。

如何维护三者的关系

View仅是传递用户请求和对数据的呈现;Presenter是事件的的决策者;Model业务逻辑执行者。

在PV中三者的关系使用的uView可以直接调用Presenter,这样就会使用的在开发过程中将Presenter作为View和Model之间的一种代理(Proxy)而不是Presenter.

那么我们就可以通过事件订阅机制来解决这个问题。

编程模型的实现

首先,要让View不能访问到Presenter,我们可以通过事件订阅机制;为所有的Presenter创建基类Presenter<IView>,泛型类型IView表示具体View实现的接口。表示View的同名只读属性在构造函数中赋值,赋值完成之后调用调用虚方法OnViewSet,使得对具体的Presenter可以重写该方法进行对View进行事件注册工作。

 namespace Handwe.Demo.MVP
{
public class Presenter<IView>
{
public IView View { get; set; } public Presenter(IView view){
this.View = view;
this.OnViewSet();
} protected virtual void OnViewSet()
{ }
}
}

其次,Presenter是通过接口的方式与View进行交互的。有时候我们要通过这个接口访问Form的一些属性、方法和事件,需要将相应的成员定义在接口上面,可能会有很多,添加的删减等。那么,我们可以将这些成员定义在一个接口中,具体View的接口继承该接口就可以了。在这里,我们相当是为所有的View接口创建了“基接口”。如下:

 namespace Handwe.Demo.MVP
{
public interface IViewBase
{
event EventHandler Load;
event EventHandler Closed;
event CancelEventHandler Closing; string ResultText
{
get;set;
} }
}

同时,也要创建所有的View创建基类ViewBase,做必要的初始化工作,如加载基础数据等:

 namespace Handwe.Demo.MVP
{
public class ViewBase : Form
{
public ViewBase()
{
this.CreatePresenter();
} protected virtual object CreatePresenter()
{
if (LicenseManager.CurrentContext.UsageMode == LicenseUsageMode.Designtime)
{
return null;
}
else
{
throw new NotImplementedException(string.Format("{0} must override the CreatedPresenter method.", this.GetType().FullName));
}
}
}
}

在ViewBase中调用CreatedPresenter(),它的实现在具体的每个View中也就是实现Presenter和View对应;

 public partial class CalculatorView : ViewBase, ICalculatorView
...
protected override object CreatePresenter()
{
return new CalculatePresenter(this);
} ...
}

实例的实现:

那边现在可以定义View的接口ICalculatorView,在这里定义了一个事件Calculating,也就是点击btnCalculate触发,还要定义三个方法,DisplayResult(int result)、DisplayMsg(stirng msg)、还有一个是Clear();具体什么用途看名称就知道了,如下:

 namespace Handwe.Demo.UnityInMVP
{
public interface ICalculatorView : IViewBase
{
event EventHandler<CalculateEventArgs> Calculating; void DisplayResult(int result); void DisplayMsg(string msg); void Clear();
}
}

这里有一个CalculateEventArgs,它是自定义的事件参数类型:

 namespace Handwe.Demo.UnityInMVP
{
public class CalculateEventArgs : EventArgs
{
public string OperationNum1 { get; set; } public string OperationNum2 { get; set; }
}
}

很简单只定义了两个属性;

接着来实现CalculatorView,代码如下:

 namespace Handwe.Demo.UnityInMVP
{
public partial class CalculatorView : ViewBase, ICalculatorView
{
public CalculatorView()
{
InitializeComponent();
} public string ResultText
{
get { return this.labResult.Text; } set{this.labResult.Text = value;}
} protected override object CreatePresenter()
{
return new CalculatorPresenter();
} #region ICalculateView Members
public event EventHandler<CalculateEventArgs> Calculating; public void DisplayResult(int result)
{
this.textBoxResult.Text = result.ToString();
} public void Clear()
{
this.textBoxOp1.Text = string.Empty;
this.textBoxOp2.Text = string.Empty; this.DisplayMsg(string.Empty);
} public void DisplayMsg(string msg)
{
this.labDisplayMsg.Text = msg;
}
#endregion private void btnCalculate_Click(object sender, EventArgs e)
{
string op1 = this.textBoxOp1.Text.Trim();
string op2 = this.textBoxOp2.Text.Trim();
this.OnCalculating(op1, op2);
} private void btnClear_Click(object sender, EventArgs e)
{
} private void btnCheck_Click(object sender, EventArgs e)
{
} protected virtual void OnCalculating(string op1, string op2)
{
if (null != this.Calculating)
{
this.Calculating(this, new CalculateEventArgs { OperationNum1 = op1, OperationNum2 = op2 });
}
}
}
}

然后我们实现事件的订阅者,这里就是CalculatePresenter:

 namespace Handwe.Demo.UnityInMVP
{
public class CalculatePresenter : Presenter<ICalculatorView>
{
public CalculatePresenter(ICalculatorView view):base(view)
{
this.Calculate = new Calculate();
} 10
public Calculate Calculate
{
get;
set;
} protected override void OnViewSet()
{
this.View.Load += (sender, args) =>
{ this.View.Clear();
}; this.View.Calculating += (sender, args) =>
{
int op1, op2;
if (!int.TryParse(args.OperationNum1, out op1))
{
this.View.DisplayMsg(string.Format("{0} type invalid.", args.OperationNum1));
return;
} if (!int.TryParse(args.OperationNum2, out op2))
{
this.View.DisplayMsg(string.Format("{0} type invalid.", args.OperationNum1));
return;
}
int result = this.Calculator.Divide(op1, op2); this.View.DisplayResult(result); this.View.Clear();
this.View.DisplayMsg("please type operation numbers.");
};
}
}
}

至此,Calculator演示实例已基本完成了,下篇将会在这个实例的基础上引入Unity、PIAB、Exception Handling,实现对Calculate的解耦和异常处理。《Unity、PIAB、Exception Handling引入MVP

http://www.cnblogs.com/coble/p/5646717.html

MVP之V和P的交互的更多相关文章

  1. Exception Handling引入MVP

    异常处理(Exception Handling)是所有系统的最基本的基础操作之一,其它的比如日志(Logging).审核(Auditing).缓存(Caching).事务处理(Transaction) ...

  2. MVP初探

    什么是MVP MVP是一种UI的架构模式,是MVC的一种变体,适用于基于事件驱动的应用框架.MVP中的M和V分别对应了MVC中的Model和View,而P代替了Controller,而它更多地体现在了 ...

  3. Unity、Exception Handling引入MVP

    什么是MVP?在“MVP初探”里就有讲过了,就是一种UI的架构模式. 简单的描述一下Unity和Exception Handling Application Block: Unity是一个轻量级的可扩 ...

  4. mvc架构和mvp架构

    mvc,mvp其实是复合模式,是多个设计模式的组合:将多个模式结合起来形成一个框架,已解决一般性问题. mvc: 既然mvc是复合模式,那么是由哪些设计模式组合的呢? 观察者设计模式:view和con ...

  5. 如何使用MVP+Dagger2+RxJava+Retrofit开发(1)

    概述 在2016年5,6月份开始在知乎上看到开发方法,那时候记得是看mvc,mvp,mvvm这三种开发模式区别,后面进一步了解到google在github上开源了使用这3种模式进行Android开发的 ...

  6. MVC和MVP设计模式

    参考博客http://www.cnblogs.com/end/archive/2011/06/02/2068512.html ####MVC模式M:model 模型V:view 视图C:control ...

  7. 架构 : 三层架构、MVC、MVP、MVVM

    1. 三层架构   将整个业务应用划分为:界面层(User Interface layer, UIL).业务逻辑层(Business Logic Layer, BLL).数据访问层(Data acce ...

  8. Android中的MVP架构初探

    说来羞愧,MVP的架构模式已经在Android领域出现一两年了.可是到今天自己才開始Android领域中的MVP架构征程. 闲话不多说,開始吧. 一.架构演变概述 我记得我找第一份工作时,面试官问我& ...

  9. mvp设计模式

    一.设计模式的简单介绍 MVP的 V 层是由UIViewController 和UIView 共同组成view 将委托presenter 对它自己的操作,(简单来说就是presenter发命令来控制v ...

随机推荐

  1. [ASP.NET Core] Middleware

    前言 本篇文章介绍ASP.NET Core里,用来处理HTTP封包的Middleware,为自己留个纪录也希望能帮助到有需要的开发人员. ASP.NET Core官网 结构 在ASP.NET Core ...

  2. Web前端开发css基础样式总结

    颜色和单位的使用    颜色        用颜色的名字表示颜色,比如:red        用16进制表示演示 比如:#FF0000        用rgb数值表示颜色,rgb(红,绿,蓝),每个值 ...

  3. (转)TortoiseSVN与VisualSVN Server搭建SVN版本控制系统

    本片主要介绍如何搭建SVN版本控制系统,主要使用工具: 1 客户端:TortoiseSVN (小乌龟) 2 服务端:VisualSVN Server 搭建出图形化管理,以及右键菜单版本控制管理的SVN ...

  4. MyEclispe 2016 CI 0发布(附下载)

    | MyEclipse 2016 CI 0下载(免费试用30天) Eclipse Mars MyEclipse 2016基于Eclipse Mars 1 (4.5.1),除了在Eclipse基础上做了 ...

  5. Sharepoint学习笔记—ECM系列—文档列表的Metedata Navigation与Key Filter功能的实现

    如果一个文档列表中存放了成百上千的文档,想要快速的找到你想要的还真不是件容易的事,Sharepoint提供了Metedata Navigation与Key Filter功能可以帮助我们快速的过滤和定位 ...

  6. android VelocityTracker 速度追踪器的使用及创建

    VelocityTracker 速度追踪 第一,创建方式: VelocityTracker  mVelocityTracker  = new VelocityTracker .obtain() 第二, ...

  7. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  8. width 、 height 与 box-sizing : border-box ,content-box 的关系

    默认 width .height的 content-box 的宽高. box-sizing 经常用来设置 width.height指定的区域 box-sizing 经常用做一些自适应的布局. 语法: ...

  9. SQL闲杂知识点汇总【2015年12月】

    2015.12.14 知识点1:DEFAULT VALUES实现插入行 --临时创建临时表 CREATE TABLE [dbo].[tblTmp] ( iTmpID ,) NOT NULL PRIMA ...

  10. js作用域问题

    <script type="text/javascript"> alert(i);//Uncaught ReferenceError: i is not defined ...