程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NBearV3教程——MVP(Model/View/Presenter)篇

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

編輯:關於.NET

版本

1.1 [2007-2-12]

簡介

本教程在《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目錄中。因此,在使用本教程的過程中如有任何疑問,可以直接參考這些代碼。

時間

<45分鐘。

正文

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文件,包含如下內容:

1using System;
2using Entities;
3
4namespace ViewInterfaces
5{
6  public interface ISampleView
7  {
8    int CategoryID { get; }
9    Category[] Categories { set; }
10    Product[] ProductsInCategory { set; }
11  }
12}

2.4 為sln新增一個名叫PresenterInterfaces的類庫工程。添加該工程到dist\NBear.Common.dll、NBear.MVP.dll和Entities工程的引用。在PresenterInterfaces中增加一個ISamplePresenter.cs文件,包含如下內容:

1using System;
2using Entities;
3using NBear.MVP;
4
5namespace PresenterInterfaces
6{
7  public interface ISamplePresenter : IPresenter
8  {
9    void GetCategories();
10    void GetProductsInCategory();
11  }
12}

2.5 為sln新增一個名叫PresenterImpls的類庫工程。添加該工程到dist\ NBear.Common.dll、NBear.IoC.dll、NBear.MVP.dll、ServiceInterfaces、ViewInterfaces、PresenterInterfaces和Entities工程的引用。在PresenterImpls中增加一個SamplePresenter.cs文件,實現前面定義的ISamplePresenter,包含如下內容:

1using System;
2using System.Collections.Generic;
3using Entities;
4using ServiceInterfaces;
5using PresenterInterfaces;
6using ViewInterfaces;
7using NBear.MVP;
8
9namespace PresenterImpls
10{
11  public class SamplePresenter : Presenter<ISampleView, ICategoryService>, ISamplePresenter
12  {
13    ISamplePresenter Members#region ISamplePresenter Members
14
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
28      if (categoriesWithProducts.Count > 0)
29      {
30        view.ProductsInCategory = model.GetCategoryByID(categoriesWithProducts[0].CategoryID).Products.ToArray();
31      }
32    }
33
34    public void GetProductsInCategory()
35    {
36      view.ProductsInCategory = model.GetCategoryByID(view.CategoryID).Products.ToArray();
37    }
38
39    #endregion
40  }
41}

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控件如下:

1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
2
3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml" >
6<head runat="server">
7  <title>Untitled Page</title>
8</head>
9<body>
10  <form id="form1" runat="server">
11  <div>
12    Choose a Category:&nbsp;<asp:DropDownList ID="listCategories" runat="server" DataTextField="CategoryName"
13      DataValueField="CategoryID">
14    </asp:DropDownList>
15    <asp:Button ID="btnLoad" runat="server" OnClick="btnLoad_Click" Text="Load Products in Selected Cateogry" /><br />
16    <br />
17    <asp:GridView ID="gridProducts" runat="server">
18    </asp:GridView>
19  </div>
20  </form>
21</body>
22</html>

3.2

在Default.aspx.cs中,我們需要實現前面定義的ISampleView接口,並使用我們已經定義的SamplePresenter。和使用NBear.IoC 中的ServiceFactory類似,我們可以非常簡單的使用NBear.MVP中定義的PresenterFactory類,通過Presenter接口得到其實現。代碼如下:

1using System;
2using System.Data;
3using System.Configuration;
4using System.Web;
5using System.Web.Security;
6using System.Web.UI;
7using System.Web.UI.WebControls;
8using System.Web.UI.WebControls.WebParts;
9using System.Web.UI.HtmlControls;
10
11using Entities;
12using ViewInterfaces;
13using PresenterInterfaces;
14using NBear.MVP;
15
16public 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代碼如下:

1<?xml version="1.0"?>
2<configuration>
3  <configSections>
4    <section name="entityConfig" type="NBear.Common.EntityConfigurationSection, NBear.Common"/>
5  <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
6 </configSections>
7  <entityConfig>
8    <includes>
9      <add key="Sample Entity Config" value="~/EntityConfig.xml"/>
10    </includes>
11  </entityConfig>
12 <castle>
13  <components>
14   <!--You can use standard castle component decleration schema to define service interface impls here-->
15   <component id="category service" service="ServiceInterfaces.ICategoryService, ServiceInterfaces" type="ServiceImpls.CategoryService, ServiceImpls"/>
16   <component id="sample presenter" service="PresenterInterfaces.ISamplePresenter, PresenterInterfaces" type="PresenterImpls.SamplePresenter, PresenterImpls"/>
17  </components>
18 </castle>
19 <appSettings/>
20  <connectionStrings>
21    <add name="Northwind" connectionString="Server=(local);Database=Northwind;Uid=sa;Pwd=sa" providerName="NBear.Data.SqlServer.SqlDbProvider"/>
22  </connectionStrings>
23  <system.web>
24    <compilation debug="true">
25      <assemblies>
26        <add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
27        <add assembly="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
28        <add assembly="System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies></compilation>
29    <authentication mode="Windows"/>
30  </system.web>
31</configuration>

3.4

運行website並浏覽Default.aspx頁面,我們就可以看到我們實現的功能了。改變Category的選擇,點擊按鈕就能查看不同的Category下的Products。

後記

如果看過其他MVP模式的實現,讀者可能會注意到某些區別。在這裡的實現中,Presenter不需要知道何時綁定數據,不需要處理事件回調,而只需要負責對view和model進行數據傳遞、驗證和過濾。何時綁定,以及哪些數據在IsPostBack時需要重新載入,哪些數據只需要在頁面初次載入時載入都是由Default頁面自己控制的。這樣做的好處是,Presenter對具體的表現層(這裡是可以PostBack的頁面)沒有任何概念上的依賴,做到了真正的解耦。即使要將該Presenter和Model應用到WindowsForm或者WPF表現層,也是輕而易舉的。

V1.1新增 –Presenter何如使用到多個Model?

上面的示例中的Presenter是比較典型的一個View對應Model(或者說Service)的情況。在實際的開發中,經常會出現一個Presenter需要訪問到多個Model的情況。

此時,可以有兩種可選的做法:

1、 具體的Presenter繼承含多個Model泛型參數的Presenter基類,如:Presenter<IView, IModel1, IModel2>, Presenter<IView, IModel1, IModel2, IModel3>等。使用和配置Presenter的方法和前文討論的方法完全一致。

2、 具體的Presenter繼承不含Model的Presenter<IView>基類。在Presenter具體實現類中,當需要使用任意Model(或者說Service時),只需要使用NBear.IoC.Service.ServiceFactory.Create().GetService<IServiceType>()方法就能獲得需要的Service的實例,然後,就能方便的調用service的方法。很明顯,使用這種方法相比方法1更靈活。因此,也是推薦的做法。

//正文結束

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved