NBearV3教程——MVP(Model/View/Presenter)

简介

    本教程在《NBearV3 Step by Step教程——IoC篇》的基础上,演示如何基于NBearV3的MVP模块实现基于NBear的IoC的MVP模式的过程。您将看到,利用封装了NBear的IoC模块的NBear.MVP模块,不仅能大大加强系统表现层的可测试性,同时能充分利用NBear已有的IoC模块获得依赖注入能力及基于IoC的分布式服务支持。

    注:在阅读本文之前,建议读者先阅读《NBearV3 Step by Step教程——IoC篇》以掌握NBearV3中有关ORM和IoC的基本知识。

    目标

    通过本教程,读者应能够全面掌握使用NBearV3的MVP模块实现表现层MVP模式。

    代码

    本教程演示创建的所有工程和代码,包含于可以从nbear.org下载的NBearV3最新源码zip包中的tutorials/MVP_Tutorial目录中。因此,在使用本教程的过程中如有任何疑问,可以直接参考这些代码。

    Step 1 下载NBearV3最新版本及准备

    1.1访问http://nbear.org,下载NBearV3的最新版本到本地目录。

    1.2 将下载的zip文件解压至C:/,您将看到,加压后的NBearV3目录中包括:dist、doc、cases、src、tutorials等目录。其中,在本教程中将会使用的是dist目录中的所有release编译版本的dll和exe和tutorials目录中之前的IoC基础教程。

    1.3 将tutorials目录中的整个IoC_Tutorial目录复制到任意其它位置,并命名为MVP_Tutorial,我们将以IoC_Tutorial为基础,演示NBearV3中基于IoC的分布式开发的知识。

 

Step 2 定义View和Presenter

    2.1 将MVP_Tutorial中的IoC_Tutorial.sln重命名为MVP_Tutorial.sln,并在VS2005开发环境中打开。

    2.2 我们知道MVP模式中,有Model、View和Presenter三个部分。在NBear.MVP中,Model部分,我们直接使用基于NBear.IoC的Service,因此,对于原来的IoC教程的代码,我们只需要额外定义View和Presenter的代码。为了充分解耦M、V、P三部分,我们将用到接口、范型和IoC技术。

    2.3 为sln新增一个名叫ViewInterfaces的类库工程。添加该工程到dist/NBear.Common.dll和Entities工程的引用。在ViewInterfaces中增加一个ISampleView.cs文件,包含如下内容:

  
  
using System; using Entities; namespace ViewInterfaces {     public interface ISampleView     {         int CategoryID { get ; }         Category[] Categories { set ; }         Product[] ProductsInCategory { set ; }     } }

    2.4 为sln新增一个名叫PresenterInterfaces的类库工程。添加该工程到dist/NBear.Common.dll、NBear.MVP.dll和Entities工程的引用。在PresenterInterfaces中增加一个ISamplePresenter.cs文件,包含如下内容:

  
  
using System; using Entities; using NBear.MVP; namespace PresenterInterfaces {     public interface ISamplePresenter : IPresenter     {         void GetCategories();         void GetProductsInCategory();     } }

    2.5 为sln新增一个名叫PresenterImpls的类库工程。添加该工程到dist/ NBear.Common.dll、NBear.IoC.dll、NBear.MVP.dll、ServiceInterfaces、ViewInterfaces、PresenterInterfaces和Entities工程的引用。在PresenterImpls中增加一个SamplePresenter.cs文件,实现前面定义的ISamplePresenter,包含如下内容:

  1. using System;
  2. using System.Collections.Generic;
  3. using Entities;
  4. using ServiceInterfaces;
  5. using PresenterInterfaces;
  6. using ViewInterfaces;
  7. using NBear.MVP;
  8. namespace PresenterImpls
  9. {
  10.     public class SamplePresenter : Presenter<ISampleView, ICategoryService>, ISamplePresenter
  11.     {
  12.         ISamplePresenter Members
  13.         
  14.         #region ISamplePresenter Members 
  15.         public void GetCategories()
  16.         {
  17.             //in presenter we can to additional data filtering, so that services can be reused more. 
  18.             List<Category> categoriesWithProducts = new List<Category>();
  19.             foreach (Category item in model.GetAllCategories())
  20.             {
  21.                 if (item.Products.Count > 0)
  22.                 {
  23.                      categoriesWithProducts.Add(item);
  24.                 }
  25.             }
  26.             view.Categories = categoriesWithProducts.ToArray();
  27.             if (categoriesWithProducts.Count > 0)
  28.             {
  29.                 view.ProductsInCategory = model.GetCategoryByID(categoriesWithProducts[0].CategoryID).Products.ToArray();
  30.             }
  31.         }
  32.         public void GetProductsInCategory()
  33.         {
  34.             view.ProductsInCategory = model.GetCategoryByID(view.CategoryID).Products.ToArray();
  35.         }
  36.         #endregion 
  37.     }
  38. }

    2.6 至此,需要的View接口、Presenter接口和实现都定义完了。对PresenterImpls,可以和ServiceImpls一样进行独立的测试。这是MVP模式最大的好处。注意,PresenterImpls中SamplePresenter继承自NBear.MVP中定义的Presenter基类,并实现IPresenter接口。该接口和基类为Presenter提供了对NBear.IoC的封装,在继承类中,可以访问Presenter基类中定义的view和model这两个protected的成员变量,分别访问关联的view和model。下面,我们将修改website以使用这些类。您将看到NBear.MVP通过 NBear.IoC获得的依赖注入能力。

 

Step 3 在website中使用View和Presenter

     3.1 在website工程中,先删除原来的Default.aspx和关联的Default.aspx.cs中的代码,并添加website到ViewInterfaces、PresenterInterfaces和PresenterImpls(其实无需添加对PresenterImpls的引用,而只需要将PresenterImpls.dll复制到website的bin目录,这里为了省区手动复制的过程才增加了它的引用)工程的引用。我们为Default.aspx增加一个DropDownList、一个Button和一个GridView控件如下:

  
  
<% @ Page Language = " C# " AutoEventWireup = " true " CodeFile = " Default.aspx.cs " Inherits = " _Default " %> <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns ="http://www.w3.org/1999/xhtml" > < head runat ="server" > < title > Untitled Page </ title > </ head > < body > < form id ="form1" runat ="server" > < div > Choose a Category: &nbsp; < asp:DropDownList ID ="listCategories" runat ="server" DataTextField ="CategoryName" DataValueField ="CategoryID" > </ asp:DropDownList > < asp:Button ID ="btnLoad" runat ="server" OnClick ="btnLoad_Click" Text ="Load Products in Selected Cateogry" />< br /> < br /> < asp:GridView ID ="gridProducts" runat ="server" > </ asp:GridView > </ div > </ form > </ body > </ html >

    3.2 在Default.aspx.cs中,我们需要实现前面定义的ISampleView接口,并使用我们已经定义的SamplePresenter。和使用NBear.IoC 中的ServiceFactory类似,我们可以非常简单的使用NBear.MVP中定义的PresenterFactory类,通过Presenter接口得到其实现。代码如下:

  
  
1 using System; 2 using System.Data; 3 using System.Configuration; 4 using System.Web; 5 using System.Web.Security; 6 using System.Web.UI; 7 using System.Web.UI.WebControls; 8 using System.Web.UI.WebControls.WebParts; 9 using System.Web.UI.HtmlControls; 10 11 using Entities; 12 using ViewInterfaces; 13 using PresenterInterfaces; 14 using NBear.MVP; 15 16 public partial class _Default : System.Web.UI.Page, ISampleView 17 { 18     private ISamplePresenter presenter; 19 20     protected void Page_Load( object sender, EventArgs e) 21     { 22 presenter = PresenterFactory.Create().GetPresenter < ISamplePresenter > ( this ); 23 if ( ! IsPostBack) 24 { 25 presenter.GetCategories(); 26 DataBind(); 27 } 28 } 29 30 protected void btnLoad_Click( object sender, EventArgs e) 31 { 32 presenter.GetProductsInCategory(); 33 gridProducts.DataBind(); 34 } 35 36 ISampleView Members #region ISampleView Members 37 38 public int CategoryID 39 { 40 get 41 { 42 if (listCategories.SelectedIndex < 0 ) 43 { 44 return - 1 ; 45 } 46 else 47 { 48 return int .Parse(listCategories.Items[listCategories.SelectedIndex].Value); 49 } 50 } 51 } 52 53 public Category[] Categories 54 { 55 set 56 { 57 listCategories.DataSource = value; 58 } 59 } 60 61 public Product[] ProductsInCategory 62 { 63 set 64 { 65 gridProducts.DataSource = value; 66 } 67 } 68 69 #endregion 70 }

    通过PresenterFactory类的Create()我们就能获得一个PresenterFactory类的singleton实例。通过GetPresenter()方法,传入Presenter的接口作为范型参数,页面自己this作为实现了ISampleView接口的实例的唯一的参数,就能得到需要的Presenter的实现类实例,这个内部的过程是通过NBear.IoC的ServiceFactory实现的,因此,可以和IoC_Adv教程中一样使用基于分布式IoC的Service作为Model。

    我们可以看到,website仅依赖于PresenterInterfaces,Prensenter的具体实现通过IoC以依赖注入方式获得。这样,我们可以方便地仅修改配置文件(无需重新编译)就改变Presenter接口对应的具体的Presenter实现类。

    特别注意,我们在使用SamplePresenter时完全没有指定Model的位置,那么SamplePresenter怎么知道哪个model对应当前的view呢?他会通过IPresenter接口(所有的Presenter需要实现该接口)的TypeOfModel属性返回的type,通过NBear.IoC.Service.ServiceFactory.GetService<type>()从IoC容器中自动获得的。也因此,它自动获得了分布式能力。

    3.3 在Web.config中的castle配置节中,因为我们的程序只需要用到category service,我们可以将product service删掉。但是,我们要在castle配置节中增加ISamplePresenter和SamplePresenter的配置。修改后的Web.config代码如下:

  
  
<? xml version="1.0" ?> < configuration > < configSections > < section name ="entityConfig" type ="NBear.Common.EntityConfigurationSection, NBear.Common" /> < section name ="castle" type ="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" /> </ configSections > < entityConfig > < includes > < add key ="Sample Entity Config" value ="~/EntityConfig.xml" /> </ includes > </ entityConfig > < castle > < components > <!-- You can use standard castle component decleration schema to define service interface impls here --> < component id ="category service" service ="ServiceInterfaces.ICategoryService, ServiceInterfaces" type ="ServiceImpls.CategoryService, ServiceImpls" /> < component id ="sample presenter" service ="PresenterInterfaces.ISamplePresenter, PresenterInterfaces" type ="PresenterImpls.SamplePresenter, PresenterImpls" /> </ components > </ castle > < appSettings /> < connectionStrings > < add name ="Northwind" connectionString ="Server=(local);Database=Northwind;Uid=sa;Pwd=sa" providerName ="NBear.Data.SqlServer.SqlDbProvider" /> </ connectionStrings > < system .web > < compilation debug ="true" > < assemblies > < add assembly ="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /> < add assembly ="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /> < add assembly ="System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" /></ assemblies ></ compilation > < authentication mode ="Windows" /> </ system.web > </ configuration >

    3.4 运行website并浏览Default.aspx页面,我们就可以看到我们实现的功能了。改变Category的选择,点击按钮就能查看不同的Category下的Products。

    后记

    如果看过其他MVP模式的实现,读者可能会注意到某些区别。在这里的实现中,Presenter不需要知道何时绑定数据,不需要处理事件回调,而只需要负责对view和model进行数据传递、验证和过滤。何时绑定,以及哪些数据在IsPostBack时需要重新载入,哪些数据只需要在页面初次载入时载入都是由Default页面自己控制的。这样做的好处是,Presenter对具体的表现层(这里是可以PostBack的页面)没有任何概念上的依赖,做到了真正的解耦。即使要将该Presenter和Model应用到WindowsForm或者WPF表现层,也是轻而易举的。

 

关于 MVP模式:

http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/MVP.mspx?mfr=true

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值