zoukankan      html  css  js  c++  java
  • ASP.NET 设计模式 MVP

    前言

    ASP.NET webform 使用后置代码页面隔离业务逻辑。但使用ASP.NET webform 做应用开发会存在以下不足:

    1. 后置代码页中混合了表现层、业务逻辑层、数据访问层的代码。出现这种情况的原因是后置代码负责事件触发,流程控制,业务规则和表现逻辑,业务逻辑和数据访问的协调者等多种角色。
    2. 后置代码页测试不方便。

    Model-View-Presenter模式

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

    1. Model:view展示或修改的业务数据。Model是对应用状态和业务功能的封装,可以看成是同时包含数据和行为的领域模型(Domain Model)
    2. View:实现可视化界面的呈现,将用户的输入委托给Presenter 。一般地,View会实现一个相应的接口。
    3. Presenter:Model和View的枢纽

    MVP具有很多变体,其中最为常用的一种变体为Passive View(被动视图)。Passive View,Model、View和Presenter之间的关系如下图所示

    clip_image002[4]_thumb

    图片来源

    View和Model之间不能直接交互,之间的交互是通过Presenter进行的

    Presenter接受View的UI请求,Presenter与Model进行通信,检索View的业务数据,完成后,Presenter更新View

    View直接依赖于Presenter,Presenter间接依赖View,Presenter直接依赖的是View实现的接口

    Passive View模式的基本特征总结

    以下引用自Artech的博文谈谈关于MVP模式中V-P交互问题

    Passive View,顾名思义,View是被动的。那么主动是谁呢?答案是Presenter。对于Presenter的主动性,我个人是这么理解的:

    • Presenter是整个MVP体系的控制中心,而不是单纯的处理View请求的人;
    • View仅仅是用户交互请求的汇报者,对于响应用户交互相关的逻辑和流程,View不参与决策,真正的决策者是Presenter;
    • View向Presenter发送用户交互请求应该采用这样的口吻:“我现在将用户交互请求发送给你,你看着办,需要我的时候我会协助你”,不应该是这样:“我现在处理用户交互请求了,我知道该怎么办,但是我需要你的支持,因为实现业务逻辑的Model只信任你”;
    • 对于绑定到View上的数据,不应该是View从Presenter上“拉”回来的,应该是Presenter主动“推”给View的;
    • View尽可能不维护数据状态,因为其本身仅仅实现单纯的、独立的UI操作;Presenter才是整个体系的协调者,它根据处理用于交互的逻辑给View和Model安排工作。

    实现一个完整的demo(代码有点多,后面给出源程序压缩包)

    1、建立领域模型层

    建立Model类库项目

    model

    Post类

       1:  [ActiveRecord("Posts")]
       2:  public class Post:ActiveRecordBase<Post>
       3:  {
       4:      [PrimaryKey("PostId")]
       5:      public int Id { get; set; }
       6:   
       7:      [Property]
       8:      public string Subject { get; set; }
       9:   
      10:      [Property]
      11:      public string Text { get; set; }
      12:   
      13:      [Property]
      14:      public DateTime DateAdded { get; set; }
      15:   
      16:      [BelongsTo("CategoryId")]
      17:      public Category Category { get; set; }
      18:   
      19:      [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
      20:      public IList<Comment> Comments { get; set; }
      21:   
      22:  }

    Category类

       1:  [ActiveRecord("Categories")]
       2:  public class Category:ActiveRecordBase<Category>
       3:  {
       4:      [PrimaryKey("CategoryId")]
       5:      public int Id { get; set; }
       6:   
       7:      [Property(Column = "Category")]
       8:      public string CategoryName { get; set; }
       9:   
      10:      [HasMany]
      11:      public IList<Post> Posts { get; set; }
      12:  }

    Comment类

       1:  [ActiveRecord("Comments")]
       2:  public class Comment : ActiveRecordBase<Comment>
       3:  {
       4:      [PrimaryKey("CommentId")]
       5:      public int Id { get; set; }
       6:   
       7:      [Property]
       8:      public string Text { get; set; }
       9:   
      10:      [Property]
      11:      public string Author { get; set; }
      12:   
      13:      [Property]
      14:      public DateTime DateAdded { get; set; }
      15:   
      16:      [BelongsTo("PostId")]
      17:      public Post Post { get; set; }
      18:   
      19:  }

    添加资源库的契约接口,该接口为业务实体持久化提供了标准方法

    IRepository接口

       1:  public interface IRepository<T> where T:class
       2:  {
       3:      T Find(int id);
       4:      void Add(T entity);
       5:      void Save(T entity);
       6:      void Remove(T entity);
       7:  }

    ICategoryRepository接口

       1:  public interface ICategoryRepository : IRepository<Category>
       2:  {
       3:      IEnumerable<Category> FindAll();
       4:  }

    IPostRepository接口

       1:  public interface IPostRepository:IRepository<Post>
       2:  {
       3:      IEnumerable<Post> FindAll();
       4:      IEnumerable<Post> FindAll(int index, int count);
       5:      int GetAllPostCount();
       6:      //IEnumerable<Post> FindAll();
       7:      //IEnumerable<Post> FindAll(int index, int count);
       8:      //IEnumerable<Post> FindBy(Query query);
       9:      //IEnumerable<Post> FindBy(Query query, int index, int count);
      10:  }

    创建领域服务类PostService

       1:  public class PostService
       2:  {
       3:      private ICategoryRepository _categoryRepository;
       4:      private IPostRepository _postRepository;
       5:      public PostService(ICategoryRepository categoryRepository,IPostRepository postRepository)
       6:      {
       7:          _categoryRepository = categoryRepository;
       8:          _postRepository = postRepository;
       9:      }
      10:      public IList<Post> GetAllPostsIn(int categoryId)
      11:      {
      12:          return _categoryRepository.Find(categoryId).Posts;
      13:      }
      14:      public IList<Comment> GetPostAllComments(int postId)
      15:      {
      16:          return _postRepository.Find(postId).Comments;
      17:      }
      18:   
      19:      public int GetAllPostCount()
      20:      {
      21:   
      22:          return _postRepository.GetAllPostCount();
      23:      }
      24:  }

    2、建立资源库(repository)

    repository

       1:  /// <summary>
       2:  /// CategoryRepository
       3:  /// </summary>
       4:   
       5:  public class CategoryRepository : ICategoryRepository
       6:  {
       7:      public IEnumerable<Category> FindAll()
       8:      {
       9:          return Category.FindAll();
      10:      }
      11:   
      12:      public Category Find(int id)
      13:      {
      14:          return Category.Find(id);
      15:      }
      16:   
      17:      public void Add(Category entity)
      18:      {
      19:          entity.Create();
      20:      }
      21:   
      22:      public void Save(Category entity)
      23:      {
      24:          entity.Save();
      25:      }
      26:   
      27:      public void Remove(Category entity)
      28:      {
      29:          entity.Delete();
      30:      }
      31:  }
      32:   
      33:   
      34:  /// <summary>
      35:  /// CommentRepository
      36:  /// </summary>
      37:  public class CommentRepository : ICommentRepository
      38:  {
      39:      public Comment Find(int id)
      40:      {
      41:          return Comment.Find(id);
      42:      }
      43:   
      44:      public void Add(Comment entity)
      45:      {
      46:          entity.Create();
      47:      }
      48:   
      49:      public void Save(Comment entity)
      50:      {
      51:          entity.Save();
      52:      }
      53:   
      54:      public void Remove(Comment entity)
      55:      {
      56:          entity.Delete();
      57:      }
      58:  }
      59:   
      60:   
      61:  /// <summary>
      62:  /// PostRepository
      63:  /// </summary>
      64:  public class PostRepository : IPostRepository
      65:  {
      66:      public IEnumerable<Post> FindAll()
      67:      {
      68:          return Post.FindAll();
      69:      }
      70:   
      71:      public IEnumerable<Post> FindAll(int index, int count)
      72:      {
      73:          return Post.FindAll().Skip(index * count).Take(count);
      74:      }
      75:   
      76:      public Post Find(int id)
      77:      {
      78:          return Post.Find(id);
      79:      }
      80:   
      81:      public void Add(Post entity)
      82:      {
      83:          entity.Create();
      84:      }
      85:   
      86:      public void Save(Post entity)
      87:      {
      88:          entity.Save();
      89:      }
      90:   
      91:      public void Remove(Post entity)
      92:      {
      93:          entity.Delete();
      94:      }
      95:   
      96:      public int GetAllPostCount()
      97:      {
      98:          ScalarQuery query = new ScalarQuery(typeof(Post), @"select count(post.Category) from Post post)");
      99:          
     100:          return int.Parse(Post.ExecuteQuery(query).ToString());
     101:      }
     102:  }
     103:   

    建立service层

       1:  public class BlogService
       2:  {
       3:      private IPostRepository _postRepository;
       4:      private ICommentRepository _commentRepository;
       5:      private ICategoryRepository _categoryRepository;
       6:      private PostService _service;
       7:   
       8:      public BlogService(ICategoryRepository categoryRepository, IPostRepository postRepository, ICommentRepository commentRepository)
       9:      {
      10:          _service = new PostService(categoryRepository, postRepository);
      11:          _categoryRepository = categoryRepository;
      12:          _postRepository = postRepository;
      13:          _commentRepository = commentRepository;
      14:      }
      15:      #region Post
      16:          public IEnumerable<Post> FindAllPost()
      17:          {
      18:              return _postRepository.FindAll();
      19:          }
      20:   
      21:          public IEnumerable<Post> FindAllPost(int index, int count)
      22:          {
      23:              return _postRepository.FindAll().Skip(index * count).Take(count);
      24:          }
      25:   
      26:          public Post FindPostBy(int id)
      27:          {
      28:              return _postRepository.Find(id);
      29:          }
      30:   
      31:          public void AddPost(Post entity)
      32:          {
      33:              _postRepository.Add(entity);
      34:          }
      35:   
      36:          public void SavePost(Post entity)
      37:          {
      38:              _postRepository.Save(entity);
      39:          }
      40:   
      41:          public void RemovePost(Post entity)
      42:          {
      43:              _postRepository.Remove(entity);
      44:          }
      45:   
      46:          public int GetAllPostCount()
      47:          {
      48:              return _postRepository.GetAllPostCount();
      49:          }
      50:   
      51:          public IList<Post> GetAllPostsIn(int categoryId)
      52:          {
      53:              return _service.GetAllPostsIn(categoryId);
      54:          }
      55:   
      56:          #endregion
      57:   
      58:      #region Category
      59:   
      60:          public IEnumerable<Category> FindAllCategories()
      61:          {
      62:              return _categoryRepository.FindAll();
      63:          }
      64:   
      65:          public Category FindCategoryBy(int id)
      66:          {
      67:              return _categoryRepository.Find(id);
      68:          }
      69:   
      70:          public void AddCategory(Category entity)
      71:          {
      72:              _categoryRepository.Add(entity);
      73:          }
      74:   
      75:          public void SaveCategory(Category entity)
      76:          {
      77:              _categoryRepository.Save(entity);
      78:          }
      79:   
      80:          public void RemoveCategory(Category entity)
      81:          {
      82:              _categoryRepository.Remove(entity);
      83:          }
      84:   
      85:          #endregion
      86:   
      87:      #region Comment
      88:   
      89:          public Comment FindComment(int id)
      90:          {
      91:              return _commentRepository.Find(id);
      92:          }
      93:   
      94:          public void AddComment(Comment entity)
      95:          {
      96:              _commentRepository.Add(entity);
      97:          }
      98:   
      99:          public void SaveComment(Comment entity)
     100:          {
     101:              _commentRepository.Save(entity);
     102:          }
     103:   
     104:          public void RemoveComment(Comment entity)
     105:          {
     106:              _commentRepository.Remove(entity);
     107:          }
     108:   
     109:          #endregion
     110:  }

    创建Presenter层

    添加IHomeView、IPostDetailView、ICategoryPostView接口(View接口解耦了Presenter与View之间的依赖)

       1:  /// <summary>
       2:  /// IHomeView
       3:  /// </summary>
       4:  public interface IHomeView
       5:  {
       6:      IEnumerable<Category> CategoryList { set; }
       7:   
       8:      IEnumerable<Post> Post { set; }
       9:   
      10:      int PostCount { set; }
      11:  }
      12:   
      13:  /// <summary>
      14:  /// IPostDetailView
      15:  /// </summary>
      16:  public interface IPostDetailView
      17:  {
      18:      IEnumerable<Category> CategoryList { set; }
      19:      Post Post { set; }
      20:      IList<Comment> Comments { set; }
      21:      event EventHandler<CommentEventArgs> NewComment;
      22:  }
      23:   
      24:   
      25:  /// <summary>
      26:  /// ICategoryPostView
      27:  /// </summary>
      28:  public interface ICategoryPostView
      29:  {
      30:      IEnumerable<Category> CategoryList { set; }
      31:   
      32:      IEnumerable<Post> Post { set; }
      33:  }
      34:   
      35:   
      36:   

    添加相应的呈现器HomePresenter、PostDetailPresenter、CategoryPostPresenter

       1:  /// <summary>
       2:  /// HomePresenter
       3:  /// </summary>
       4:  public class HomePresenter:IPresenter
       5:  {
       6:      private IHomeView _homeView;
       7:      private BlogService _service;
       8:      public HomePresenter(IHomeView homeView,BlogService service)
       9:      {
      10:          _homeView = homeView;
      11:          _service = service;
      12:      }
      13:      public void Display()
      14:      {
      15:          _homeView.CategoryList = _service.FindAllCategories();
      16:          _homeView.Post = _service.FindAllPost(0, 10);
      17:          _homeView.PostCount = _service.GetAllPostCount();
      18:      }
      19:  }
      20:   
      21:   
      22:  /// <summary>
      23:  /// PostDetailPresenter
      24:  /// </summary>
      25:  public class PostDetailPresenter : IPresenter
      26:  {
      27:      private IPostDetailView _postDetailView;
      28:      private BlogService _service;
      29:      private int _postId;
      30:      public PostDetailPresenter(IPostDetailView postDetailView, BlogService service, int postId)
      31:      {
      32:          _postDetailView = postDetailView;
      33:          _service = service;
      34:          _postId = postId;
      35:          _postDetailView.NewComment += new EventHandler<Event.CommentEventArgs>(_postDetailView_NewComment);
      36:      }
      37:   
      38:      void _postDetailView_NewComment(object sender, Event.CommentEventArgs e)
      39:      {
      40:          Comment comment=new Comment ();
      41:          comment.Author=e.CommentAuthor;
      42:          comment.Text=e.CommentText;
      43:          comment.DateAdded = DateTime.Now;
      44:          comment.Post = _service.FindPostBy(_postId);
      45:          _service.AddComment(comment);
      46:      }
      47:      public void Display()
      48:      {
      49:          _postDetailView.CategoryList = _service.FindAllCategories();
      50:          _postDetailView.Post = _service.FindPostBy(_postId);
      51:          _postDetailView.Comments = _service.FindPostBy(_postId).Comments;
      52:      }
      53:  }
      54:   
      55:   
      56:  /// <summary>
      57:  /// CategoryPostPresenter
      58:  /// </summary>
      59:  public class CategoryPostPresenter : IPresenter
      60:  {
      61:      private ICategoryPostView _categoryPostView;
      62:      private BlogService _service;
      63:      private int _categoryId;
      64:      public CategoryPostPresenter(ICategoryPostView categoryPostView, BlogService service, int categoryId)
      65:      {
      66:          _categoryPostView = categoryPostView;
      67:          _service = service;
      68:          _categoryId = categoryId;
      69:      }
      70:      public void Display()
      71:      {
      72:          _categoryPostView.CategoryList = _service.FindAllCategories();
      73:          _categoryPostView.Post = _service.GetAllPostsIn(_categoryId);
      74:      }
      75:  }

    三个呈现器实现共同的呈现接口IPresenter

       1:  public interface IPresenter
       2:  {
       3:      void Display();
       4:  }

    创建web应用程序 作为view

    index.aspx.cs

       1:  public partial class Index : System.Web.UI.Page, IHomeView
       2:  {
       3:      IPresenter _presenter;
       4:      int _pageCount;
       5:      protected override void OnPreInit(EventArgs e)
       6:      {
       7:   
       8:          _presenter = new HomePresenter(this, ObjectFactory.GetInstance<BlogService>());
       9:          base.OnPreInit(e);
      10:      }
      11:      protected void Page_Load(object sender, EventArgs e)
      12:      {
      13:          _presenter.Display();
      14:      }
      15:   
      16:      public IEnumerable<Model.Category> CategoryList
      17:      {
      18:          set
      19:          {
      20:              
      21:              rptCategory.DataSource = value;
      22:              rptCategory.DataBind();
      23:          }
      24:      }
      25:   
      26:      public IEnumerable<Model.Post> Post
      27:      {
      28:          set
      29:          {
      30:              rptPostList.DataSource = value;
      31:              rptPostList.DataBind();
      32:          }
      33:      }
      34:   
      35:      public int PostCount
      36:      {
      37:          set { _pageCount = value; }
      38:      }
      39:  }

    CategoryPost.aspx.cs

       1:  public partial class CategoryPost : System.Web.UI.Page, ICategoryPostView
       2:  {
       3:      IPresenter _presenter;
       4:      protected override void OnPreInit(EventArgs e)
       5:      {
       6:          int categoryId;
       7:          int.TryParse(Request.QueryString["categoryid"], out categoryId);
       8:   
       9:          _presenter = new CategoryPostPresenter(this, ObjectFactory.GetInstance<BlogService>(), categoryId);
      10:          base.OnPreInit(e);
      11:      }
      12:      protected void Page_Load(object sender, EventArgs e)
      13:      {
      14:          _presenter.Display();
      15:      }
      16:   
      17:      public IEnumerable<Model.Category> CategoryList
      18:      {
      19:          set
      20:          {
      21:              rptCategory.DataSource = value;
      22:              rptCategory.DataBind();
      23:          }
      24:      }
      25:   
      26:      public IEnumerable<Model.Post> Post
      27:      {
      28:          set
      29:          {
      30:              rptPostList.DataSource = value;
      31:              rptPostList.DataBind();
      32:          }
      33:      }
      34:  }

    PostDetail.aspx.cs

       1:  public partial class PostDetail : System.Web.UI.Page,IPostDetailView
       2:  {
       3:      IPresenter _presenter;
       4:      public event EventHandler<CommentEventArgs> NewComment;
       5:      protected virtual void OnNewComment(CommentEventArgs e)
       6:      {
       7:          if (NewComment != null)
       8:          {
       9:              NewComment(this, e);
      10:          }
      11:      }   
      12:   
      13:      protected override void OnPreInit(EventArgs e)
      14:      {
      15:          int postId;
      16:          int.TryParse(Request.QueryString["postId"], out postId);
      17:   
      18:          _presenter = new PostDetailPresenter(this, ObjectFactory.GetInstance<BlogService>(), postId);
      19:          base.OnPreInit(e);
      20:      }
      21:      protected void Page_Load(object sender, EventArgs e)
      22:      {
      23:          _presenter.Display();
      24:      }
      25:   
      26:      public IEnumerable<Model.Category> CategoryList
      27:      {
      28:          set
      29:          {
      30:              rptCategory.DataSource = value;
      31:              rptCategory.DataBind();
      32:          }
      33:      }
      34:   
      35:      public Model.Post Post
      36:      {
      37:          set {
      38:              lbltitle.Text = value.Subject;
      39:              lblDateAdded.Text = value.DateAdded.ToShortDateString();
      40:              litContent.Text = value.Text;
      41:          }
      42:      }
      43:   
      44:      public IList<Model.Comment> Comments
      45:      {
      46:          set
      47:          {
      48:              rptCommentList.DataSource = value;
      49:              rptCommentList.DataBind();
      50:          }
      51:      }
      52:   
      53:      protected void btnCommit_Click(object sender, EventArgs e)
      54:      {
      55:          int postId;
      56:          int.TryParse(Request.QueryString["postid"], out postId);
      57:          
      58:          CommentEventArgs eventArgs = new CommentEventArgs(txtText.Text, txtAuthor.Text,postId);
      59:          OnNewComment(eventArgs);
      60:      }    
      61:  }

    MVP模式中的顺序图

    sequencediagram

    下载地址:源代码下载

    参考资料:谈谈关于MVP模式中V-P交互问题

         Professional ASP.NET Design Patterns

         在ASP.NET中实现Model-View-Presenter(MVP)

         使用ASP.NET实现Model View Presenter(MVP)

  • 相关阅读:
    node.js代码
    弹性盒和多列布局
    浏览器兼容性
    图片整合与宽高自适应
    百度分享自定义设置
    设置Cookie,登录记住用户登录信息,获取用户登录过得信息
    验证用户是否登录,是否有过注册信息
    循环显示切换
    ajax提交表单 验证
    简单易用的点击展开伸缩效果
  • 原文地址:https://www.cnblogs.com/whx1973/p/2806480.html
Copyright © 2011-2022 走看看