Thinking In Design Pattern——MVP模式演绎

简介:

原文《Thinking In Design Pattern——MVP模式演绎》不知为何丢失了,故重新整理了一遍。

目录

  • What Is MVP
  • Domain Model
  • StubRepositoty
  • IView & Presenter
  • View
  • Ioc容器StructureMap

开篇

忙碌的9月,工作终于落定,新公司里的框架是MVP+Linq,对于MVP虽然不熟,但有MVC的基础,花了两天时间研究了MVP,故作此博文,留作参考。

Model-View-Presenter(模型-视图-呈现器,MVP)模式的重点是让Presenter控制整个表示层的逻辑流。MVP模式由如下三个不同部分组成:

  • 模型表示视图显示或者修改的业务数据,包括业务逻辑和领域相关的逻辑。
  • 视图通过呈现器显示模型数据,并将用户输入委托给呈现器。
  • 呈现器被视图调用来显示从模型中“拉”出来的数据并处理用户输入。

What Is MVP

了解了MVP设计模式后,我以一个简单的例子阐述MVP模式在企业级架构中的应用,如下图给出了企业级分层设计的ASP.NET应用程序的典型体系结构(实际还要更复杂些):

 

下面的我将以一个简单的案例(出自《ASP.NET》设计模式)详解MVP思想的应用,当然MVP和MVC一样都是属于表现层的设计模式,我将参考上述两幅图中的分层思想来创建应用程序,下图为分层体系结构创建完毕时解决方案目录:

OK,接下来我们从头开始来创建我们的应用程序,首先我们要分清楚需求(建立一个简单的购物流程Demo),了解需求后我们再抽象出模型(Category,Product)。

建立简单的领域模型:

复制代码
namespace Eyes.MVP.Model
{
    public class Category
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
复制代码
复制代码
public class Product
{
    public int Id { get; set; }
    public Category Category { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
}
复制代码

接着,为Product和Category添加资源库的契约接口,该接口为业务实体持久化提供了标准方法,我建议把这部分代码放到infrastructure层中:

 

复制代码
public interface ICategoryRepository
{
    IEnumerable<Category> FindAll();
    Category FindBy(int id);
}

public interface IProductRepository
{
    IEnumerable<Product> FindAll();
    Product FindBy(int id);
}
复制代码

最后添加领域服务类ProductService,基于接口编程的思想使用资源库契约接口(IxxxRepository)来协调Product和Category的操作:

建立Domain Model之后,需要为资源库(仓储)提供数据,所以创建StubRepository:

StubRepositoty

创建名为StubRepositoty的类库,DataContext为我们的资源库提供数据:

当数据就为之后,我们就可以实现Model项目中定义的资源库契约接口:

这样我们就完成了StubRepository项目,有关Infrastructure和Repository我不做详细介绍,所以我简单处理。当然本片博客的核心是MVP,接下来详解View和Presenter关系。

View & Presenter

切换Presenter项目中,添加IHomeView接口,这个接口定义了电子商务网页的视图,在首页上显示商品目录以及最畅销的商品:

public interface IHomeView
   {
       IEnumerable<Category> CategoryList { set; }
   }

接着,定义一个IHomePagePresenter接口,这个接口的目的是实现代码松散耦合并有助于测试:

public interface IHomePagePresenter
    {
        void Display();
    }

最后,添加一个HomePagePresenter,这个呈现器从ProductService中检索到的Product和Category数据来填充视图属性,这儿完美体现了Presenter的作用:

复制代码
   public class HomePagePresenter : IHomePagePresenter
    {
        private readonly IHomeView _view;
        private readonly ProductService _productService;

        public HomePagePresenter(IHomeView view, ProductService productService)
        {
            _view = view;
            _productService = productService;
        }

        public void Display()
        {
            _view.TopSellingProduct = _productService.GetBestSellingProducts();
            _view.CategoryList = _productService.GetAllCategories();
        }
    }
复制代码

接下来是包含一个分类中所有商品的视图ICategoryProductsView:

复制代码
public interface ICategoryProductsView
    {
        int CategoryId { get; }
        IEnumerable<Product> CategoryProductList { set; }
        IEnumerable<Category> CategoryList { set; }
    }
复制代码

然后再创建CategoryProductsPresenter,他与HomePagePresenter相似:从ProductService中获取到的分类商品来更新视图,但他稍有不同,他要求视图提供CategoryId:

复制代码
public class CategoryProductsPresenter : ICategoryProductsPresenter
    {
        private readonly ICategoryProductsView _view;
        private readonly ProductService _productService;

        public CategoryProductsPresenter(ICategoryProductsView view, ProductService productService)
        {
            _view = view;
            _productService = productService;
        }

        public void Display()
        {
            _view.CategoryProductList = _productService.GetAllProductsIn(_view.CategoryId);
            _view.Category = _productService.GetCategoryBy(_view.CategoryId);
            _view.CategoryList = _productService.GetAllCategories();
        }
    }
复制代码

接下来我们还要创建下一个视图用来表示Product的详细视图,该视图显示有关特定商品的详细信息并可以添加到购物车中(Session),在该视图之前我们还需要创建一些支撑类:

WebBasket类简单的使用当前会话来存放和检索商品集合,接着我们在添加一个Navigation,用来重定向:

实现IPageNavigator:

编写好辅助类之后,我们在创建商品详细视图,这儿需要注意一下ProduceId这个属性,和之前一样也是只读的,通过QueryString得到ProductId:

接下来,添加一个相应的ProductDetailPresenter(实现IProductDetailPresenter接口):

最后添加购物车视图,IBasketView接口显示顾客的购物车中的所有商品以及一个用户商品目录导航的商品分类列表:

相信接下来你已经驾轻就熟了,创建BasketPresenter,用来控制Model和View之间的数据交互:

这样我们就完成了Presenter项目,接下来我们就可以关注视图实现了,由于篇幅有限,我挑选一个典型模块分析,具体代码可以在此下载:

MVP实现关注点的分离,集中管理相关的逻辑,View关注与UI交互,Model关注与业务逻辑,Presenter协调管理View和Model,是整个体系的核心。Model与View无关,具有极大复用性。 
MVP通过将将主要的逻辑局限于Presenter,是它们具有更好的可测试性。至于并行开发,个人觉得在真正的开发中,意义到不是很大,现在开发这大多是多面手,呵!

Presenter通过接口调用View降低了Presenter对View的依赖,但是View依然可以调用Presenter,从而导致了很多开发人员将Presenter当成了一个Proxy,所以我们的目的是降低View对Presenter的依赖。

“所以我更倾向于View并不知道按钮点击后回发生什么事,如Update数据,但是点击后界面有什么光线,水纹,这个应该是View关心的,View应该更注重的是和用户交互的反应。”着正是本文的观点:View仅仅将请求递交给Presenter,Presenter在适当的时候来驱动View!

View:

为了使布局统一和减少冗余代码,我们将创建Master Page和User Control:

CategoryList.ascx,用来显示所有的目录集合:

为了能让Presenter为他绑定数据,我们需要创建一个方法:

接下来,再添加一个用户控件ProductList.ascx,用来显示商品的集合:

最后再添加一个Master Page,并为其添加一个:

接下来添加一张ProductDetail.aspx页面,因为比较典型,所以我选他来作为分析,让其实现IProductDetailView接口:

这里我想提一下Ioc容器:StructureMap

  Ioc

传统的控制流,从客户端创建服务时(new xxxService()),必须指定一个特定服务实现(并且对服务的程序集添加引用),Ioc容器所做的就是完全将这种关系倒置过来(倒置给Ioc容器),将服务注入到客户端代码中,这是一种推得方式(依赖注入)。术语”控制反转“,即客户放弃代码的控制,将其交给Ioc容器,也就是将控制从客户端代码倒置给容器,所以又有人称作好莱坞原则”不要打电话过来,我们打给你“。实际上,Ioc就是使用Ioc容器将传统的控制流(客户端创建服务)倒置过来,将服务注入到客户端代码中。

总之一句话,客户端代码能够只依赖接口或者抽象类或基类或其他,而不关心运行时由谁来提供具体实现。

使用Ioc容器如StructureMap,首先配置依赖关系(即当向Ioc容器询问特定的类型时将返回一个具体的实现),所以这又叫依赖注入:

通常我们希望在启动是配置依赖关系,一般在Application_Start事件中调用ConfigureStructureMap方法:

小结

MVP设计模式我匆忙总结了一下,由于经验不足,不足之处,还望多多指点。

88x31.png
本博客为 木宛城主原创,基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。

本文转自木宛城主博客园博客,原文链接:http://www.cnblogs.com/OceanEyes/p/think_in_design_pattern_mvp.html,如需转载请自行联系原作者
目录
相关文章
|
1月前
|
算法 C++
运用C++ 策略模式的艺术(The Art of Applying Strategy Pattern)
运用C++ 策略模式的艺术(The Art of Applying Strategy Pattern)
16 0
|
移动开发 算法 Linux
艾伟:C# Design Patterns (2) - Strategy
Strategy Pattern (策略模式) 所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用;而不是将策略、具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易。
990 0
|
移动开发 算法 Linux
艾伟_转载:C# Design Patterns (2) - Strategy
Strategy Pattern (策略模式) 所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用;而不是将策略、具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易。
894 0
|
存储 程序员 C#
艾伟_转载:C# Design Patterns (5) - Prototype
本帖介绍 Prototype Pattern (原型模式),并以一个「人事招聘程序」作为示例来说明。--------------------------------------------------------本帖的示例下载点:http://files.cnblogs.com/WizardWu/090713.zip第一个示例为 Console Mode (控制台应用程序) 项目,第二个示例为 ASP.NET 网站项目。
1413 0
|
前端开发 容器 JavaScript
零元学Expression Design 4 - Chapter 2 熟悉Design并且快速设计出Silverlight网页
原文:零元学Expression Design 4 - Chapter 2 熟悉Design并且快速设计出Silverlight网页 本章将用带大家熟悉Design 4并制作简易的网页版面,也会让你了解如...
1087 0