惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - ruinet

WCF通用服务请求类 WCF中使用扩展行为来验证连接的用户 Microsoft.Practices.Unity依赖注入使用实例 简洁的Asp.net菜单控件 Windows Mobile无线打印的实现 - ruinet 使用HTML,CSS快速导出数据到Excel - ruinet 软件技术网站精选 - ruinet CakePHP架构入门 - ruinet 升级Sql Server 2000到Sql Server 2005中要注意的问题 - ruinet asp.net web开发综合技能 编写第一个Silverlight程序 Saas学习 - ruinet 在Windows Mobile上控制输入法 - ruinet - 博客园 在Windows Mobile创建桌面快捷方式 在仿真设备中使用主机网络 CSS,JavaSript,Html实用小代码 重启PocketPC移动设备 使用Ajax控件引发性能问题 智能移动项目打包发布经验交流
使用MVP模式实现B/S和C/S平台的功能通用
ruinet · 2010-04-11 · via 博客园 - ruinet

2010-04-11 21:40  ruinet  阅读(3335)  评论()    收藏  举报

        在某些项目中我们可能需要同时开发支持B/S和C/S模式的应用,在这样的背景下如何最大化的保证功能和代码通用性和适应性,就显得尤为重要了。在传统的B/S和C/S模式下,往往都是直接在页面UI类下直接进行控件的绑定、数据的验证和对业务逻辑的访问。这样的设计缺点是:依赖UI测试困难,控件代码和业务逻辑代码交织增加维护的难度。当业务需求变更时,需要转换或支持另一种客户端时都需要重新编写大量的页面逻辑。而采用Model-View-Presenter(MVP)可以保持各层功能的独立,使页面代码更加干净,测试更方便。

       MVP简介

         MVP是从经典的MVC模式演变而来,Model实现业务逻辑,Presenter实现程序逻辑,将View和Model完全分离,View实现页面接口。如下图:

             

从MVP模型图上我们可以了解到:

   1 仅有Presenter能访问Model进行数据检索执行业务逻辑。

   2 View依赖Presenter,包含Presenter实体。

   3.Presenter不依赖具体的View实体,只包含View的接口(Presenter到View间的连线非直接连接)。

   4.View不能访问Model.


      为了说明使用MVP可以实现B/S和C/S模式下功能的通用,准备了一个小的实例来说明。要实现的功能就类似博客文章的分类的管理,可以浏览所有的分类添加删除分类。这个功能同时在asp.net和Windows Form中实现。

       Model (业务逻辑)

实现的业务逻辑:查询、添加、删除分类。类图如下:

         View接口

View接口是MVP模式中代码量最少的地方,但是如果要想快速看一个页面实现的功能就看View接口提供的对象。

本实例中ICategoryView成员如下类图:

 1.AddedCategory:获取要输入的添加的分类;

 2.Categories :显示要所有的分类;

 3.DeletedCategory:获取输入的要删除的分类;

 4.IsFirstLoaded :获取页面是否是第一显示,如果是第一次加载的话就显示出现有的所有分类。

 5.StatusMessage :显示当前的操作处理状态。

     Presenter

CatePresenter包括一个ICategoryView对象,类图如下:

 

Presenter仅包括View的接口,这样就可以测试时不需依赖具体的窗口或页面。

CategoryPresenter实现呈现层的逻辑,包括简单的输入检查,输入反馈,View控制和访问Model业务逻辑。

CategoryPresenter的具体实现:

代码

public class CategoryPresenter
{
    
private ICategoryView _View;public CategoryPresenter(ICategoryView view)
    {
      _View 
= view;
    }
    
public void OnCategorySave()
    {
      
if (string.IsNullOrEmpty(_View.AddedCategory))
      {
        
this._View.StatusMessage = "分类名不能为空";
        
return;
      }
      
if (PostsLogic.ExistCategory(this._View.AddedCategory))
      {
        _View.StatusMessage 
= "分类名已存在!";
        
return;
      }
      PostsLogic.AddCategory(_View.AddedCategory);
this._View.Categories = PostsLogic.GetCategories();
    }
    
public void OnViewLoaded()
    {
      
if (this._View.IsFirstLoaded)
      {
        _View.Categories 
= PostsLogic.GetCategories();
      }
    }
    
public void OnCategoryDelete()
    {
      
if (string.IsNullOrEmpty(_View.DeletedCategory))
      {
        
this._View.StatusMessage = "请选择要删除的分类名";
        
return;
      }
if (!PostsLogic.ExistCategory(_View.DeletedCategory))
      {
        
this._View.StatusMessage = _View.DeletedCategory + ",分类名不存在!";
        
return;
      }
      PostsLogic.RemoveCategory(_View.DeletedCategory);
      
this._View.StatusMessage = "删除成功!";this._View.Categories = PostsLogic.GetCategories();
    }
  }

CategoryPresenter初始化:

     Windows Form中:

代码

public partial class FrmCategory : Form,ICategoryView
{
        CategoryPresenter _Presenter;
        
public FrmCategory()
        {
            InitializeComponent();
            _Presenter 
= new CategoryPresenter(this);
        }
}

 .aspx页面中:

public partial class _Default : System.Web.UI.Page ,ICategoryView
{
    
private CategoryPresenter prsenter; 
    
protected override void OnInit(EventArgs e)
    {
      
base.OnInit(e);
      prsenter 
= new CategoryPresenter(this);
    }
}

处理显示删除添加事件:

代码

 private void btnAdd_Click(object sender, EventArgs e)
{
            
this._Presenter.OnCategorySave();
}
private void btnDelete_Click(object sender, EventArgs e)
{
            
this._Presenter.OnCategoryDelete();
}

    实现View接口

Presenter完成后就只需将aspx页面或windows Form窗体继承并实现ICategoryView接口,同时定义CategoryPresenter实体,就可以通用数据逻辑。

.aspx.cs页面完整代码:

代码

public partial class _Default : System.Web.UI.Page ,ICategoryView
{
  
private CategoryPresenter prsenter;
  
private string deleteCategory;
    
protected void Page_Load(object sender, EventArgs e)
    {
      prsenter.OnViewLoaded();
    }
    
protected override void OnInit(EventArgs e)
    {
      
base.OnInit(e);
      prsenter 
= new CategoryPresenter(this);
    }
#region ICategoryView 成员
    
public string AddedCategory
    {
      
get { return this.txtCategory.Text.Trim(); }
    }
public string DeletedCategory
    {
      
get { return this.deleteCategory; }
    }
public string StatusMessage
    {
      
set { this.lblStatusMessage.Text = value; }
    }
public System.Collections.Generic.IList<string> Categories
    {
      
set 
      {
        
this.repCategories.DataSource = value;
        
this.repCategories.DataBind();
      }
    }
    
public bool IsFirstLoaded
    {
      
get { return !this.IsPostBack; }
    }
    
#endregion
    
protected void repCategories_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
      
if (e.CommandName == "delete")
      {
        deleteCategory 
= ((Label)e.Item.FindControl("lblCategory")).Text;
        prsenter.OnCategoryDelete();
      }
    }
    
protected void btnSave_Click(object sender, EventArgs e)
    {
      prsenter.OnCategorySave();
    }
}

 Windwos Form窗体完整代码:

代码

 public partial class FrmCategory : Form,ICategoryView
    {
        CategoryPresenter _Presenter;
        
public FrmCategory()
        {
            InitializeComponent();
            _Presenter 
= new CategoryPresenter(this);
        }
#region ICategoryView 成员public string DeletedCategory
        {
            
get 
            {
                
if (this.listBox1.SelectedIndex == -1)
                {
                    
return string.Empty;
                }
                
return this.listBox1.SelectedValue.ToString();
            }
        }
        
public string AddedCategory
        {
            
get { return this.txtCategory.Text; }
        }
        
public string StatusMessage
        {
            
set { MessageBox.Show(value); }
        }
public IList<string> Categories
        {
            
set 
            {
                
this.listBox1.DataSource = null;
            
this.listBox1.DataSource = value;
            }
        }
        
public bool IsFirstLoaded
        {
          
get 
          {
            
return true;
          }
        }
        
#endregionprivate void btnAdd_Click(object sender, EventArgs e)
        {
            
this._Presenter.OnCategorySave();
        }
private void btnDelete_Click(object sender, EventArgs e)
        {
            
this._Presenter.OnCategoryDelete();
        }
private void FrmCategory_Load(object sender, EventArgs e)
        {
            
this._Presenter.OnViewLoaded();
        }
}

页面显示如图:

附上本实例代码

   总结

    本文通过一个小的实例介绍MVP模式在asp.net 和windows Form中的分离通用呈现层的数据逻辑,使业务逻辑跟具体的UI窗体分离,保持了页面内容代码的干净。使用MVP模式最重要的好处是方便测试,同时有助于设计人员和编程人员分工。了解MVP的精髓,在于了解Model 、View和Preseneter之间的通信,同时结合实际情况加以选择。