网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 设计资源 > .Net编程 > 正文

谈.net开发人员应该熟悉的开发模式

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务

我们总会有这样一个经验:一个系统最不容易也最不应该变化的部分是领域逻辑,最容易变化也最应该变化的是数据的呈现方式。

  在java的各种应用中可以说是到处可见mvc,j2ee贯穿mvc的概念,android的开发方式也是类mvc的,mvc结构对于做过java应用的人而言简直就是司空见惯。而在.net这边,由于之前微软为大家提供的各种winform、asp.net项目典范(比如那个petshop series)将“三层”概念很好的灌输到了.net程序员的大脑中,许多.net开发者凡是做个东西都要搬出自己最拿手的IModel、IDAL这样的神器。

  其实mvc与所谓的“三层架构”是两个层次上的东西,前者是一种结构模式,而后者则是分层的角度去说。

  一件很奇怪的事情,许多人知道“三层”却不知道mvc,其实这要归结与.net的早期开发技术asp.net和winform这些page controller的典范让许多人对三层夸夸其谈却对mvc视而不见甚至一无所知。什么是page controller模式呢?搞.net的大多都用过winform和webform,这种xxxform用起来很直观,我们想要做一个程序,ok,最简单的方式就是拖拖拽拽几个控件,然后在一个叫code behind的东西里写这些UI事件的处理逻辑,加一大堆变量用于记录数据和状态,这样一个程序就能出炉。这种开发方式对于一些小软件系统的开发其实效率还是蛮高的,后来人们看到其弊端---一旦修改UI,事件处理就要跟着变,但是业务还是那个业务,凭什么要修改非UI的代码?于是有人提出“三层”,最朴素的理解就是将原本那堆事件处理里的code分成业务代码和数据库访问代码并转移到其它类中,做多了就把那坨UI叫做UI,那坨业务代码叫做BLL,那坨DAO叫做DAL。也就是这种架构:

image

  而对于j2ee的开发者来说熟悉的是下图。 

image

  (说明:这两幅图copy自是daxnet文)

  MVC是什么

  MVC是一个很经典的结构,并且其又其思想衍生出很多变种比如MVP,MVVP。传统的MVC结构之一是这样的(拿主动型mvc来说):

image

  比如web开发(比如asp.net mvc或者是java的web开发方式),view就是纯web页面或者webservice,当提交一个表单/调用webservice或者ajax后会将数据提交给controller(当然期间可能会经过各种filterchain、listener这样的东西)controller调用相应的业务模块来处理这个请求,最终结果会更新View的显示。

  MVP

  对于非天然mvc的框架

  对于asp.net/winform而言,虽然可以通过改造让其支持mvc结构的开发(比如通过定制IHttpModule、IHttpHandler云云),但是在企业看来这些都算是邪门武功(因为这样会丧失xxxform在开发上的很多特性比如快速开发)。大多数使用的是mvp模式。什么是mvp呢?其实mvp是mvc的一个变种。因为用winform或者webform的话form始终是个阻碍mvc开发的问题。那么好,我们仍然使用designer和codebehind,其实一个架构设计的好坏是取决于人而不是具体的技术的,只要我们OO一时强page controller一样好用。

image

  在MVP模式中我们需要自己定制各个View(web页面或者窗体)对应的IView和IPresenter、IModel。IView要对IPresenter暴露操作UI、数据绑定的接口,IPresenter对IView要暴露当UI事件触发需要调用的接口,IPresenter根据IView传递过来的请求调用业务接口并根据结果操作UI。举个简单的例子,一个计算“x+y=?”的程序。如果我们这样定义IPresenter和IView

  1. public interface IPresenter 
  2.     { 
  3.         IView View { getset; } 
  4.         void CalculateResult(); 
  5.     } 
  6.  
  7. public interface IView 
  8.     { 
  9.         IPresenter Presenter { getset; } 
  10.         void ShowResult(string result); 
  11.         int ValueOne { get; } 
  12.         int ValueTwo { get; } 
  13.     } 

IPresenter的实现如下(这里从简把IModel去掉了)

Presenter

  1. namespace ClientLibrary 
  2.     public class Presenter : IPresenter 
  3.     { 
  4.         private IView _view; 
  5.         public IView View 
  6.         { 
  7.             get 
  8.             { 
  9.                 return _view; 
  10.             } 
  11.             set 
  12.             { 
  13.                 _view = value; 
  14.                 _view.Presenter = this
  15.             } 
  16.         } 
  17.  
  18.         private static readonly string RESULT_FORMATTER = "{0}+{1},the result is {2}"
  19.         public void CalculateResult() 
  20.         { 
  21.             if (_view != null
  22.             { 
  23.                 var result = string.Format(RESULT_FORMATTER, _view.ValueOne, _view.ValueTwo, _view.ValueOne + _view.ValueTwo); 
  24.                 _view.ShowResult(result); 
  25.                 this.A = 123; 
  26.             } 
  27.         } 
  28.         private int _a; 
  29.         public int A 
  30.         { 
  31.             set 
  32.             { 
  33.                 A = value; 
  34.             } 
  35.         } 
  36.     } 

View的实现如下(那silverlight为例,换成别的也行)

MainPage

  1. namespace debug 
  2.     public partial class MainPage : UserControl, IView 
  3.     { 
  4.         public MainPage() 
  5.         { 
  6.             InitializeComponent(); 
  7.         } 
  8.  
  9.         private IPresenter _presenter; 
  10.  
  11.         private void btn_Click(object sender, RoutedEventArgs e) 
  12.         { 
  13.             if (_presenter != null
  14.             { 
  15.                 _presenter.CalculateResult(); 
  16.             } 
  17.             #region hidden 
  18.             /*int total = 0; 
  19.             try 
  20.             { 
  21.                 total = int.Parse(tb1.Text) + int.Parse(tb2.Text); 
  22.                 MessageBox.Show("计算结果:" + total.ToString()); 
  23.             } 
  24.             catch (Exception ex) 
  25.             { 
  26.                 MessageBox.Show("出错啦" + ex.ToString()); 
  27.             } 
  28.             finally 
  29.             { 
  30.                 tb1.Text = string.Empty; 
  31.                 tb2.Text = string.Empty; 
  32.             }*/ 
  33.             #endregion 
  34.  
  35.         } 
  36.  
  37.         public IPresenter Presenter 
  38.         { 
  39.             get 
  40.             { 
  41.                 return _presenter; 
  42.             } 
  43.             set 
  44.             { 
  45.                 _presenter = value; 
  46.             } 
  47.         } 
  48.  
  49.         public void ShowResult(string result) 
  50.         { 
  51.             MessageBox.Show(result); 
  52.         } 
  53.  
  54.         public int ValueOne 
  55.         { 
  56.             get { return int.Parse(tb1.Text); } 
  57.         } 
  58.  
  59.         public int ValueTwo 
  60.         { 
  61.             get { return int.Parse(tb2.Text); } 
  62.         } 
  63.     } 

 

一个很简单的东西,看上去写成的要多些那么一坨东西,但是好处是显而易见的,就是更换view非常方便,根本不用去改你的IPresenter、Presenter和业务。一切都是接口调用而不依赖具体实现,这就是好处。

  你必须要懂的MVVM

  对于.NET平台的开发人员,托微软的福分我们拥有一种更为强大的模型---MVVM。这应该算是做WPF/Silverlight应用的人必懂的一种结构,WPF/silverlight天生支持数据绑定和命令绑定(不过sl在命令绑定上还比较弱),这就为我们使用MVVM创造了可能。

  View是什么呢,纯的View只有xaml或者附带必要的只与View本身相关逻辑代码。ViewModel,你可以把它理解为View具体呈现内容所依赖数据的一个抽象,在MVVM中View与ViewModel总会有一种绑定关系,一旦ViewModel中被绑定的数据发生改变View上的数据就会跟着变,相反也有可能,比如你的账号密码框内容发生变化,关联的ViewModel中的数据就会被框架自动通知到。

  在wpf/silverlight中,绑定是通过xaml语法来完成(虽然你可以选择用c#来写但不符合mvvm的宗旨),并且绑定双方的通知机制是有框架来完成,也就是说一个会xaml和blend的美工只需事先和coder商量下“咱们的xx和xx是在哪个ViewModel上叫XXX的属性的XXX属性……”问题之后就可以各干各的了。那么ViewModel怎么写,咋view中又怎么绑定到viewmodel呢?首先我们谈ViewModel。

  说道ViewModel你需要知道依赖属性和依赖对象的概念,这是wpf/silverlight的基础所以不多说。有两种方式写ViewModel。第一种是自己去实现INotifyPropertyChanged接口,并在属性变化时去调用NotifyPropertyChanged事件。

  为了方便我们定义一个ViewModelBase的抽象基类,然后让其他ViewModel继承这个基类。

ViewModelBase

  1. public abstract class ViewModelBase : System.ComponentModel.INotifyPropertyChanged, IDisposable  
  2.     {  
  3.         public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;  
  4.         protected void OnPropertyChanged(string propertyName)  
  5.         {  
  6.             if (PropertyChanged != null)  
  7.             {  
  8.                 var arg = new System.ComponentModel.PropertyChangedEventArgs(propertyName);  
  9.                 PropertyChanged(this, arg);  
  10.             }  
  11.         }  
  12.         public virtual void Dispose()  
  13.         {  
  14.             
  15.         }  
  16.     } 

DemoViewModel

  1. public class DemoViewModel : ViewModelBase 
  2.  
  3.     { 
  4.  
  5.         #region fields 
  6.  
  7.         private string _propertyA; 
  8.  
  9.         #endregion 
  10.  
  11.         #region presentation properties 
  12.  
  13.         public string PropertyA 
  14.  
  15.         { 
  16.  
  17.             get 
  18.  
  19.             { 
  20.  
  21.                 return _propertyA; 
  22.  
  23.             } 
  24.  
  25.             set 
  26.  
  27.             { 
  28.  
  29.                 if (_propertyA != value) 
  30.  
  31.                 { 
  32.  
  33.                     _propertyA = value; 
  34.  
  35.                     base.OnPropertyChanged("PropertyA"); 
  36.  
  37.                 } 
  38.  
  39.             } 
  40.  
  41.         } 
  42.  
  43.         #endregion 
  44.  
  45.     } 

第二种是利用DependencyObject和DependencyProperty。

PeopleItemViewModel

  1. public class PeopleItemViewModel : DependencyObject, IPeopleItemViewModel 
  2.     { 
  3.         public PeopleItemViewModel() 
  4.         { 
  5.              
  6.         } 
  7.         public static readonly DependencyProperty SimpleUserDataProperty = DependencyProperty.Register("SimpleUserData"typeof(SimpleUserData), typeof(PeopleItemViewModel)); 
  8.         public static readonly DependencyProperty RelativeSimpleUserDataProperty = DependencyProperty.Register("RelativeSimpleUserData"typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel)); 
  9.         public static readonly DependencyProperty AllSimpleUserDataProperty = DependencyProperty.Register("AllSimpleUserData"typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel)); 
  10.  
  11.         public SimpleUserData SimpleUserData 
  12.         { 
  13.             get 
  14.             { 
  15.                 return (SimpleUserData)base.GetValue(SimpleUserDataProperty); 
  16.             } 
  17.             set 
  18.             { 
  19.                 if (!base.CheckAccess()) 
  20.                 { 
  21.                     Dispatcher.Invoke(new Action( 
  22.                         () => 
  23.                         { 
  24.                             SimpleUserData = value; 
  25.                         })); 
  26.                 } 
  27.                 else 
  28.                     base.SetValue(SimpleUserDataProperty, value); 
  29.             } 
  30.         } 
  31.         public ObservableCollection<SimpleUserData> RelativeSimpleUserData 
  32.         { 
  33.             get 
  34.             { 
  35.                 return (ObservableCollection<SimpleUserData>)base.GetValue(RelativeSimpleUserDataProperty); 
  36.             } 
  37.             set 
  38.             { 
  39.                 if (!base.CheckAccess()) 
  40.                 { 
  41.                     Dispatcher.Invoke(new Action( 
  42.                         () => 
  43.                         { 
  44.                             RelativeSimpleUserData = value; 
  45.                         })); 
  46.                 } 
  47.                 else 
  48.                 { 
  49.                     base.SetValue(RelativeSimpleUserDataProperty, value); 
  50.                     var collectionView = CollectionViewSource.GetDefaultView(value); 
  51.                     collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending)); 
  52.                 } 
  53.             } 
  54.         } 
  55.         public ObservableCollection<SimpleUserData> AllSimpleUserData 
  56.         { 
  57.             get 
  58.             { 
  59.                 return (ObservableCollection<SimpleUserData>)base.GetValue(AllSimpleUserDataProperty); 
  60.             } 
  61.             set 
  62.             { 
  63.                 if (!base.CheckAccess()) 
  64.                 { 
  65.                     Dispatcher.Invoke(new Action( 
  66.                         () => 
  67.                         { 
  68.                             AllSimpleUserData = value; 
  69.                         })); 
  70.                 } 
  71.                 else 
  72.                 { 
  73.                     base.SetValue(AllSimpleUserDataProperty, value); 
  74.                     var collectionView = CollectionViewSource.GetDefaultView(value); 
  75.                     collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending)); 
  76.                 } 
  77.             } 
  78.         } 

 

在View中绑定ViewModel。

  为了方便,我们可以在app.xaml中将需要的viewmode放到全局资源字典中。

image

  然后再我们的vs视图设计器Properties(中文版显示的是“属性”)页上选择为绑定源设置绑定目标(包括source和path等)以及必要的值转换器等等即可。

imageimageimage

  (PS:虽然vs很强大,但个人还是建议熟悉xaml的绑定语法,想当初用vs2008搞wpf的时候貌似还没有这么方便的设计器。。。)

  • 上一篇资讯: .NET中AOP的几种实现方案
  • 设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
    版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师