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

推荐订阅源

The Hacker News
The Hacker News
F
Full Disclosure
Cloudbric
Cloudbric
Blog — PlanetScale
Blog — PlanetScale
W
WeLiveSecurity
N
News and Events Feed by Topic
T
Troy Hunt's Blog
V2EX - 技术
V2EX - 技术
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
GbyAI
GbyAI
C
Check Point Blog
B
Blog RSS Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Recorded Future
Recorded Future
The Last Watchdog
The Last Watchdog
N
News and Events Feed by Topic
T
The Blog of Author Tim Ferriss
O
OpenAI News
V
V2EX
人人都是产品经理
人人都是产品经理
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Security @ Cisco Blogs
C
Cisco Blogs
Security Latest
Security Latest
S
Security Affairs
V
Visual Studio Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
Last Week in AI
Last Week in AI
AWS News Blog
AWS News Blog
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
PCI Perspectives
PCI Perspectives
博客园_首页
U
Unit 42
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
Project Zero
Project Zero
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
N
Netflix TechBlog - Medium
L
LINUX DO - 热门话题
H
Hacker News: Front Page

博客园 - ruinet

WCF通用服务请求类 WCF中使用扩展行为来验证连接的用户 Microsoft.Practices.Unity依赖注入使用实例 简洁的Asp.net菜单控件 Windows Mobile无线打印的实现 使用HTML,CSS快速导出数据到Excel 软件技术网站精选 CakePHP架构入门 升级Sql Server 2000到Sql Server 2005中要注意的问题 asp.net web开发综合技能 编写第一个Silverlight程序 Saas学习 在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  阅读(3337)  评论()    收藏  举报

        在某些项目中我们可能需要同时开发支持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之间的通信,同时结合实际情况加以选择。