溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

發(fā)布時間:2021-11-25 13:58:04 來源:億速云 閱讀:162 作者:柒染 欄目:編程語言

這篇文章給大家介紹.NET程序員應(yīng)該熟悉的開發(fā)模式是什么,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

我們總會有這樣一個經(jīng)驗:一個系統(tǒng)最不容易也最不應(yīng)該變化的部分是領(lǐng)域邏輯,最容易變化也最應(yīng)該變化的是數(shù)據(jù)的呈現(xiàn)方式。

在Java的各種應(yīng)用中可以說是到處可見MVC,J2EE貫穿MVC的概念,android的開發(fā)方式也是類MVC的,MVC結(jié)構(gòu)對于做過Java應(yīng)用的人而言簡直就是司空見慣。而在.NET這邊,由于之前微軟為大家提供的各種winform、ASP.NET項目典范(比如那個petshop series)將“三層”概念很好的灌輸?shù)搅?NET程序員的大腦中,許多.NET開發(fā)者凡是做個東西都要搬出自己最拿手的IModel、IDAL這樣的神器。

其實MVC與所謂的“三層架構(gòu)”是兩個層次上的東西,前者是一種結(jié)構(gòu)模式,而后者則是分層的角度去說。

一件很奇怪的事情,許多人知道“三層”卻不知道MVC,其實這要歸結(jié)與.NET的早期開發(fā)技術(shù)ASP.NET和winform這些page controller的典范讓許多人對三層夸夸其談卻對MVC視而不見甚至一無所知。什么是page controller模式呢?搞.NET的大多都用過winform和webform,這種xxxform用起來很直觀,我們想要做一個程序,ok,最簡單的方式就是拖拖拽拽幾個控件,然后在一個叫code behind的東西里寫這些UI事件的處理邏輯,加一大堆變量用于記錄數(shù)據(jù)和狀態(tài),這樣一個程序就能出爐。這種開發(fā)方式對于一些小軟件系統(tǒng)的開發(fā)其實效率還是蠻高的,后來人們看到其弊端---一旦修改UI,事件處理就要跟著變,但是業(yè)務(wù)還是那個業(yè)務(wù),憑什么要修改非UI的代碼?于是有人提出“三層”,最樸素的理解就是將原本那堆事件處理里的code分成業(yè)務(wù)代碼和數(shù)據(jù)庫訪問代碼并轉(zhuǎn)移到其它類中,做多了就把那坨UI叫做UI,那坨業(yè)務(wù)代碼叫做BLL,那坨DAO叫做DAL。也就是這種架構(gòu):

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

而對于J2EE的開發(fā)者來說熟悉的是下圖。

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

(說明:這兩幅圖copy自是daxnet文)

MVC是什么

MVC是一個很經(jīng)典的結(jié)構(gòu),并且其又其思想衍生出很多變種比如MVP,MVVP。傳統(tǒng)的MVC結(jié)構(gòu)之一是這樣的(拿主動型MVC來說):

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

比如web開發(fā)(比如ASP.NET MVC或者是Java的web開發(fā)方式),view就是純web頁面或者webservice,當(dāng)提交一個表單/調(diào)用webservice或者ajax后會將數(shù)據(jù)提交給controller(當(dāng)然期間可能會經(jīng)過各種filterchain、listener這樣的東西)controller調(diào)用相應(yīng)的業(yè)務(wù)模塊來處理這個請求,最終結(jié)果會更新View的顯示。

MVP

對于非天然MVC的框架

對于ASP.NET/winform而言,雖然可以通過改造讓其支持MVC結(jié)構(gòu)的開發(fā)(比如通過定制IHttpModule、IHttpHandler云云),但是在企業(yè)看來這些都算是邪門武功(因為這樣會喪失xxxform在開發(fā)上的很多特性比如快速開發(fā))。大多數(shù)使用的是mvp模式。什么是mvp呢?其實mvp是MVC的一個變種。因為用winform或者webform的話form始終是個阻礙MVC開發(fā)的問題。那么好,我們?nèi)匀皇褂胐esigner和codebehind,其實一個架構(gòu)設(shè)計的好壞是取決于人而不是具體的技術(shù)的,只要我們OO一時強page controller一樣好用。

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

在MVP模式中我們需要自己定制各個View(web頁面或者窗體)對應(yīng)的IView和IPresenter、IModel。IView要對IPresenter暴露操作UI、數(shù)據(jù)綁定的接口,IPresenter對IView要暴露當(dāng)UI事件觸發(fā)需要調(diào)用的接口,IPresenter根據(jù)IView傳遞過來的請求調(diào)用業(yè)務(wù)接口并根據(jù)結(jié)果操作UI。舉個簡單的例子,一個計算“x+y=?”的程序。如果我們這樣定義IPresenter和IView

public interface IPresenter       {           IView View { get; set; }           void CalculateResult();       }   public interface IView       {           IPresenter Presenter { get; set; }           void ShowResult(string result);           int ValueOne { get; }           int ValueTwo { get; }       }

IPresenter的實現(xiàn)如下(這里從簡把IModel去掉了)

Presenter

namespace ClientLibrary  {      public class Presenter : IPresenter      {          private IView _view;          public IView View          {              get             {                  return _view;              }              set             {                  _view = value;                  _view.Presenter = this;              }          }           private static readonly string RESULT_FORMATTER = "{0}+{1},the result is {2}";          public void CalculateResult()          {              if (_view != null)              {  var result = string.Format(RESULT_FORMATTER, _view.ValueOne, _view.ValueTwo, _view.ValueOne + _view.ValueTwo);                  _view.ShowResult(result);                  this.A = 123;              }          }          private int _a;          public int A          {              set             {                  A = value;              }          }      }  }

View的實現(xiàn)如下(那silverlight為例,換成別的也行)

MainPage

namespace debug  {      public partial class MainPage : UserControl, IView      {          public MainPage()          {              InitializeComponent();          }           private IPresenter _presenter;   private void btn_Click(object sender, RoutedEventArgs e)          {              if (_presenter != null)              {                  _presenter.CalculateResult();              }              #region hidden              /*int total = 0;              try              {  total = int.Parse(tb1.Text) + int.Parse(tb2.Text);  MessageBox.Show("計算結(jié)果:" + total.ToString());              }              catch (Exception ex)              {                  MessageBox.Show("出錯啦" + ex.ToString());              }              finally              {                  tb1.Text = string.Empty;                  tb2.Text = string.Empty;              }*/             #endregion           }           public IPresenter Presenter          {              get             {                  return _presenter;              }              set             {                  _presenter = value;              }          }           public void ShowResult(string result)          {              MessageBox.Show(result);          }           public int ValueOne          {              get { return int.Parse(tb1.Text); }          }           public int ValueTwo          {              get { return int.Parse(tb2.Text); }          }      }  }

一個很簡單的東西,看上去寫成的要多些那么一坨東西,但是好處是顯而易見的,就是更換view非常方便,根本不用去改你的IPresenter、Presenter和業(yè)務(wù)。一切都是接口調(diào)用而不依賴具體實現(xiàn),這就是好處。

你必須要懂的MVVM

對于.NET平臺的開發(fā)人員,托微軟的福分我們擁有一種更為強大的模型---MVVM。這應(yīng)該算是做WPF/Silverlight應(yīng)用的人必懂的一種結(jié)構(gòu),WPF/silverlight天生支持?jǐn)?shù)據(jù)綁定和命令綁定(不過sl在命令綁定上還比較弱),這就為我們使用MVVM創(chuàng)造了可能。

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

View是什么呢,純的View只有xaml或者附帶必要的只與View本身相關(guān)邏輯代碼。ViewModel,你可以把它理解為View具體呈現(xiàn)內(nèi)容所依賴數(shù)據(jù)的一個抽象,在MVVM中View與ViewModel總會有一種綁定關(guān)系,一旦ViewModel中被綁定的數(shù)據(jù)發(fā)生改變View上的數(shù)據(jù)就會跟著變,相反也有可能,比如你的賬號密碼框內(nèi)容發(fā)生變化,關(guān)聯(lián)的ViewModel中的數(shù)據(jù)就會被框架自動通知到。

在wpf/silverlight中,綁定是通過xaml語法來完成(雖然你可以選擇用c#來寫但不符合mvvm的宗旨),并且綁定雙方的通知機制是有框架來完成,也就是說一個會xaml和blend的美工只需事先和coder商量下“咱們的xx和xx是在哪個ViewModel上叫XXX的屬性的XXX屬性……”問題之后就可以各干各的了。那么ViewModel怎么寫,咋view中又怎么綁定到viewmodel呢?首先我們談ViewModel。

說道ViewModel你需要知道依賴屬性和依賴對象的概念,這是wpf/silverlight的基礎(chǔ)所以不多說。有兩種方式寫ViewModel。***種是自己去實現(xiàn)INotifyPropertyChanged接口,并在屬性變化時去調(diào)用NotifyPropertyChanged事件。

為了方便我們定義一個ViewModelBase的抽象基類,然后讓其他ViewModel繼承這個基類。

ViewModelBase

public abstract class ViewModelBase : System.ComponentModel.INotifyPropertyChanged, IDisposable       {           public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;           protected void OnPropertyChanged(string propertyName)           {               if (PropertyChanged != null)               {         var arg = new System.ComponentModel.PropertyChangedEventArgs(propertyName);                   PropertyChanged(this, arg);               }           }           public virtual void Dispose()           {                        }       }
DemoViewModel public class DemoViewModel : ViewModelBase      {          #region fields          private string _propertyA;          #endregion          #region presentation properties          public string PropertyA          {              get              {                  return _propertyA;              }              set              {                  if (_propertyA != value)                {                      _propertyA = value;                   base.OnPropertyChanged("PropertyA");                  }              }        }          #endregion    }

第二種是利用DependencyObject和DependencyProperty。

PeopleItemViewModel

public class PeopleItemViewModel : DependencyObject, IPeopleItemViewModel      {          public PeopleItemViewModel()          {                        }  public static readonly DependencyProperty SimpleUserDataProperty = DependencyProperty.Register("SimpleUserData", typeof(SimpleUserData), typeof(PeopleItemViewModel));  public static readonly DependencyProperty RelativeSimpleUserDataProperty = DependencyProperty.Register("RelativeSimpleUserData", typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));  public static readonly DependencyProperty AllSimpleUserDataProperty = DependencyProperty.Register("AllSimpleUserData", typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));           public SimpleUserData SimpleUserData          {              get             {                  return (SimpleUserData)base.GetValue(SimpleUserDataProperty);              }              set             {                  if (!base.CheckAccess())                  {                      Dispatcher.Invoke(new Action(                          () =>                          {                              SimpleUserData = value;                          }));                  }                  else                     base.SetValue(SimpleUserDataProperty, value);              }          }          public ObservableCollection<SimpleUserData> RelativeSimpleUserData          {              get             {  return (ObservableCollection<SimpleUserData>)base.GetValue(RelativeSimpleUserDataProperty);              }              set             {                  if (!base.CheckAccess())                  {                      Dispatcher.Invoke(new Action(                          () =>                          {                              RelativeSimpleUserData = value;                          }));                  }                  else                 {  base.SetValue(RelativeSimpleUserDataProperty, value);  var collectionView = CollectionViewSource.GetDefaultView(value);  collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending));                  }              }          }          public ObservableCollection<SimpleUserData> AllSimpleUserData          {              get             {        return (ObservableCollection<SimpleUserData>)base.GetValue(AllSimpleUserDataProperty);              }              set             {                  if (!base.CheckAccess())                  {                      Dispatcher.Invoke(new Action(                          () =>                          {                              AllSimpleUserData = value;                          }));                  }                  else                 {  base.SetValue(AllSimpleUserDataProperty, value);  var collectionView = CollectionViewSource.GetDefaultView(value);  collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending));                  }              }          }  }

在View中綁定ViewModel。

為了方便,我們可以在app.xaml中將需要的viewmode放到全局資源字典中。

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么

然后再我們的vs視圖設(shè)計器Properties(中文版顯示的是“屬性”)頁上選擇為綁定源設(shè)置綁定目標(biāo)(包括source和path等)以及必要的值轉(zhuǎn)換器等等即可。

.NET程序員應(yīng)該熟悉的開發(fā)模式是什么 .NET程序員應(yīng)該熟悉的開發(fā)模式是什么 .NET程序員應(yīng)該熟悉的開發(fā)模式是什么

雖然vs很強大,但個人還是建議熟悉xaml的綁定語法,想當(dāng)初用vs2008搞wpf的時候貌似還沒有這么方便的設(shè)計器。

關(guān)于.NET程序員應(yīng)該熟悉的開發(fā)模式是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI