架構 : 三層架構、MVC、MVP、MVVM


1、 三層架構

 
將整個業務應用划分為:界面層(User Interface layer, UIL)、業務邏輯層(Business Logic Layer, BLL)、數據訪問層(Data access layer, DAL)。
 
 
1:界面層: 主要是指用戶交互的界面。用於接收用戶輸入的數據和顯示處理后用戶需要的數據。如果邏輯層相當強大和完善,無論表現層如何定義和更改,邏輯層都能完善地提供服務。
 
2:業務邏輯層: UI層和DAL層之間的橋梁實現業務邏輯。業務邏輯具體包含:驗證、計算、業務規則等等。
 
3:數據訪問層:與數據庫打交道。主要實現對數據的增、刪、改、查。將存儲在數據庫中的數據提交給業務層,同時將業務層處理的數據保存到數據庫。(當然這些操作都是基於UI層的。用戶的需求反映給界面(UI),UI反映給BLLBLL反映給DALDAL進行數據的操作,操作后再一一返回,直到將用戶所需數據反饋給用戶)。
 
   

1.1、 規則

  1. 最關鍵的,UI層只能作為一個外殼,不能包含任何業務邏輯(BizLogic)的處理過程。只有少量(或者沒有)SQL語句或者存儲過程的調用,並且這些語句保證不會修改數據。
  2. 設計時應該從BLL出發,而不是UI出發。BLL層在API上應該實現所有BizLogic(以面向對象的方式)。如果把UILayer拿掉,項目還能在Interface/API的層次上提供所有功能)。
  3. 不管數據層是一個簡單的SqlHelper也好,還是帶有Mapping過的Classes也好,應該在一定的抽象程度上做到系統無關(DAL可以移植到其他類似環境的項目)。
  4. 不管使用COM+(Enterprise Service),還是Remoting,還是WebService之類的遠程對象技術,不管部署的時候是不是真的分別部署到不同的服務器上,最起碼在設計的時候要做這樣的考慮,更遠的,還得考慮多台服務器通過負載均衡作集群(三個模塊,可以分別運行於不同的服務器)。

1.2、 優勢

1,結構清晰、耦合度低,

2,可維護性高,可擴展性高;

3,利於開發任務同步進行;容易適應需求變化

1.3、 劣勢

1、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼

2、增加了代碼量,增加了工作量,增加了復雜度。

 

2、 MVC

 

 

如果說ORM(Object Relation Mapping)等框架是數據訪問層的框架模式,解除了業務邏輯和數據之間的耦合,業務邏輯不再關心底層數據如何存儲和讀取。所有數據呈現給業務邏輯層的就是一個個的對象。

MVC則是表現層的框架模式。用於解除業務邏輯和視圖之間的耦合。從而易於擴展,便於測試。

 

MVC誕生於1979年,體現了“關注點分離”這一設計方針,它將一個人機交互應用涉及的功能分為三部分。

2.1、 Model

Model對應應用狀態和業務功能的封裝,可以將它理解為同時包含數據和行為的領域模型(Domain Model)。Model接受Controller的請求並完成相應的業務處理,在應用狀態改變的時候可以向View發出相應的通知。

2.2、 View

View實現可視化界面的呈現並捕捉最終用戶的交互操作。View可以直接調用Model查詢其狀態信息,而Model也可以在自己的狀態發生改變時,主動通知View。

2.3、 Controller

Contoller是M和V之間的連接器,用於控制應用程序的流程。View捕獲用戶交互操作后直接轉發給Contoller,后者完成相應的UI邏輯。如果需要涉及業務功能的調用,Contoller會直接調用Model及修改Model狀態。Contoller也可以主動控制原View或創建新的View對用戶交互操作予以響應。
 

2.1、 MVC使用的誤區

2.1.1、 把Model理解成實體類(Entity)

在MVC中Model應該包含2部分功能,一部分是處理業務邏輯,一部分是提供View顯示的數據。

它應該是業務邏輯真正的實現層。所以Model的實際上是Business Model(業務模型)。而Controller僅僅起一個“橋梁”作用,它負責把View的請求轉發給Model,再負責把Model處理結束的消息通知View。Controller的存在是為了使UI界面、UI邏輯、業務邏輯之間分離。

2.1.2、 大量業務邏輯代碼堆積在Controller端

MVC中的控制器,內里封裝了通訊,容易變成大而全 的高度耦合的集中器。
  1. 控制器中寫業務代碼
    1. UI邏輯可以寫在Controller中,而業務邏輯應該在Model里,Controller只是去調用它們。
  2. 控制器變得依賴信息數據中心或數據庫,對象將間接地通過控制器的action耦合在一起

    1. 可以通過引入IOC容器來解決

2.2、 總結

MVC最早的定義畢竟是79年提出的,到現在GUI編程環境,業務復雜程度都有了很大改變。當采用MVC模式設計UI應用時,一般會根據開發框架的特點來對Model,View和Contoller設置一個明確的界限,同時為它們之間的交互制定一個更加嚴格的規則。

3、 MVC變體

在軟件發展歷程中出現了一些MVC變體,它們遵循定義在MVC中的基本原則,但對三元素直接的交互制定了更為嚴格的規范。

3.1、 MVP

  1. MVP適用於基於事件驅動的應用框架中,如Asp.net Web Forms 和Windows Forms應用。
  2. MVP中嚴格禁止View和Model間的直接交互,必需通過Presenter來完成。Model的獨立性得到了真正的體現,它不僅僅與可視化元素的呈現(View)無關,與UI處理邏輯也無關。使用MVP的應用是用戶驅動而不是Model驅動,所以Model不需要主動通知view。
  3. MVP模式中的V代表的是一個接口,一個將UI界面提煉而抽象出來的接口。接口意味着任何實現了該接口的界面,都能夠復用已有的Presenter和Model代碼。是真正意義上的隔離View的細節和復雜性的模式,降低了Presenter對View的依賴。帶來的好處就是定義在Presenter中的UI處理邏輯變得易於測試。
 
MVP中Presenter與Model的交互很清晰,僅體現為Presenter對Model的單向調用。而View與Presenter直接的交互方式就成了MVP的核心。按照View與Presenter的交互方式依據View本身的職責范圍,Martin Folwer將MVP分為PV(Passive View)和SC(Supervising Contoller)兩種模式。

3.1.1、 PV

view是難以測試的,通過讓它盡可能不涉及UI處理邏輯來使它不需要測試,這就是PV模式的目的。
這意味着需要將View中的UI元素通過屬性的形式暴露出來。將所有UI處理邏輯全部定義到Presenter中。定義在IView里的只有屬性。

3.1.2、 SC

PV需要將View中可供操作的UI元素定義在對應的接口中,對於一些復雜的富客戶端應用的View來說,接口成員的數量可能會非常多,這無疑提升了代碼量和Presenter的復雜度。
SC則將一些單純,獨立的UI邏輯交由View自身來完成。當然它處理的數據是Presenter實時推送給它的。View盡可能不維護數據狀態。定義在IView里的接口盡量只包含方法,且是無返回值的方法(單向傳遞消息)。
 
Models:
public class Employee
{
     public  string  Id {  get private  set ; }
     public  string  Name {  get private  set ; }
     public  string  Gender {  get private  set ; }
     public  DateTime BirthDate {  get private  set ; }
     public  string  Department {  get private  set ; }
 
     public  Employee( string  id, string  name, string  gender,DateTime birthDate, string  department)
     {
         Id          = id;
         Name        = name;
         Gender      = gender;
         BirthDate   = birthDate;
         Department  = department;
     }
}
 
public  class  EmployeeRespository
{
     private  static  IList<Employee> employees;
 
     static  EmployeeRespository()
     {
         employees =  new  List<Employee>()
         {
             new  Employee( "001" , "張三" , "男" , new  DateTime(1981,8,24), "銷售部" ),
             new  Employee( "002" , "李四" , "男" , new  DateTime(1981,8,24), "人事部" ),
             new  Employee( "003" , "王五" , "女" , new  DateTime(1981,8,24), "人事部" )
         };
     }
 
     public  IEnumerable<Employee> GetEmployees( string  department =  "" )
     {
         if  ( string .IsNullOrEmpty(department))
         {
             return  employees;
         }
         return  employees.Where(e => e.Department == department).ToArray();
     }
}

 
Presenter、IView
public class EmployeePresenter
{
     public  IEmployeeView View {  get private  set ; }
     public  EmployeeRespository Respository {  get private  set ; }
 
     public  EmployeePresenter(IEmployeeView view)
     {
         this .View = view;
         this .Respository =  new  EmployeeRespository();
         this .View.DepartmentSelected += OnDepartmentSelected;
     }
 
     public  void  Initialize()
     {
         IEnumerable<Employee> employees =  this .Respository.GetEmployees();
         this .View.BindEmployees(employees);
         string [] departments
             new  string []{
                 "" , "銷售部" , "采購部" , "人事部"
             };
         this .View.BindDepartments(departments);
     }
 
     protected  void  OnDepartmentSelected( object  sender, DepartmentSelectedEventArgs args)
     {
         string  department = args.Department;
         var  employees =  this .Respository.GetEmployees(department);
         this .View.BindEmployees(employees);
     }
}
 
 
public  interface  IEmployeeView
{
     void  BindEmployees(IEnumerable<Employee> employees);
     void  BindDepartments(IEnumerable< string > departments);
     event  EventHandler<DepartmentSelectedEventArgs> DepartmentSelected;
}
public  class  DepartmentSelectedEventArgs : EventArgs
{
     public  string  Department {  get private  set ; }
     public  DepartmentSelectedEventArgs( string  department)
     {
         this .Department = department;
     }
}
WinForm實現的UI界面
public  partial  class  Form1 : Form, IEmployeeView
{
     private  EmployeePresenter Presenter{  get private  set ; }
     public  Form1()
     {
         InitializeComponent();
 
         Presenter =  new  EmployeePresenter( this );
         Presenter.Initialize();      
     }
     public  event  EventHandler<DepartmentSelectedEventArgs> DepartmentSelected;
 
     public  void  BindDepartments(IEnumerable< string > departments)
     {
         this .comboBox1.DataSource = departments;
     }
 
     public  void  BindEmployees(IEnumerable<Employee> employees)
     {
         this .listBox1.DataSource = employees;
         this .listBox1.DisplayMember =  "Name" ;
     }
 
     private  void  comboBox1_SelectedIndexChanged( object  sender, EventArgs e)
     {
         string  department = ( string ) this .comboBox1.SelectedItem;
         DepartmentSelectedEventArgs eventArgs =  new  DepartmentSelectedEventArgs(department);
         DepartmentSelected?.Invoke(sender, eventArgs);
     }
}

 

WebForm實現的UI界面
public  partial  class  Default : Page, IEmployeeView
{
     public  EmployeePresenter Presenter {  get private  set ; }
     public  event  EventHandler<DepartmentSelectedEventArgs> DepartmentSelected;
 
     public  Default()
     {
         this .Presenter =  new  EmployeePresenter( this );
     }
 
     protected  void  Page_Load( object  sender, EventArgs e)
     {
         if  (! this .IsPostBack)
         {
             this .Presenter.Initialize();
         }
     }
 
     protected  void  ButtonSearch_Click( object  sender, EventArgs e)
     {
         string  department =  this .DropDownListDepartments.SelectedValue;
         DepartmentSelectedEventArgs eventArgs =  new  DepartmentSelectedEventArgs(department);
         if  ( null  != DepartmentSelected)
         {
             DepartmentSelected( this , eventArgs);
         }
     }
 
     public  void  BindEmployees(IEnumerable<Employee> employees)
     {
         this .GridViewEmployees.DataSource = employees;
         this .GridViewEmployees.DataBind();
     }
 
 
     public  void  BindDepartments(IEnumerable< string > departments)
     {
         this .DropDownListDepartments.DataSource = departments;
         this .DropDownListDepartments.DataBind();
     }
}

在MVP里,可以根據User Story來首先設計和開發Presenter。在這個過程中,View是很簡單的,能夠把信息顯示清楚就可以了。在后面,根據需要再隨便更改View, 而對Presenter沒有任何的影響了。

如果要實現的UI比較復雜,而且相關的顯示邏輯還跟Model有關系,可以在View和 Presenter之間放置一個Adapter。由這個 Adapter來訪問Model和View,避免兩者之間的關聯。而同時,因為Adapter實現了View的接口,從而可以保證與Presenter之 間接口的不變。這樣就可以保證View和Presenter之間接口的簡潔,又不失去UI的靈活性。

3.2、 MVVM

MVVM模式中,一個ViewModel和一個View匹配,它沒有MVP中的IView接口,而是完全的和View綁定,所有View中的修改變化,都會自動更新到ViewModel中,同時ViewModel的任何變化也會自動同步到View上顯示。
這種自動同步之所以能夠的原因是ViewModel中的屬性都實現了observable這樣的接口,也就是說當使用屬性的set的方法,都會同時觸發屬性修改的事件,使綁定的UI自動刷新。(在WPF中,這個observable接口是 INotifyPropertyChanged; 在knockoutjs中,是通過函數ko.observable() 和ko.observrableCollection()來實現的)
在MVP中,V是接口IView, 解決對於界面UI的耦合; 而MVVM則干脆直接使用ViewModel和UI無縫結合, ViewModel直接就能代表UI。但是MVVM做到這點是要依賴具體的平台和技術實現。 這也就是為什么ViewModel不需要實現接口的原因,因為對於具體平台和技術的依賴,本質上使用MVVM模式就是不能替換UI的使用平台的。
MVVM的提出源於WPF,主要是用於分離應用界面層和業務邏輯層。WPF/Siverlight是基於數據驅動開發的。
在MVC和MVP模式中, 開發View層的是程序員, 雖然UI/UE團隊會做很多工作, 但這個層的"實現者"仍然是程序員。
而在WPF開發中將View層的代碼邏輯抽取出來,並使View層很純粹以便完全讓美工去打造它。相應地, 需要將View層的相應邏輯抽取到一個代碼層上,以便讓程序員專注在這里。

3.3、 Asp.net Mvc 應用中的請求處理

  • 每個HTTP請求的目標是Controller中的一個Action,具體體現為定義在Controller類型中的一個public方法。所以對請求的處理最終體現為對目標Controller對象的激活和對目標Action方法的執行。
  • Controller的類型和Action方法的名稱及作為Action方法的部分參數可以直接通過請求的Url解析出來。
  • 通過一個攔截器(Interceptor)對抵達Web服務器的HTTP請求進行攔截。這個攔截器根據當前請求解析出目標Controller的類型和對應的Action方法的名稱,隨后目標Controller被激活,相應的Action方法被執行。
  • Action方法執行過程中,可以調用Model獲取相應的數據及改變其狀態。在Action執行的最后階段一般會創建一個View,后者最終被轉換為HTML以HTTP響應的形式返回到客戶端。
  • 綁定在View上的數據稱為ViewModel,來源於Model或者基於顯示要求進行的簡單邏輯計算。它與MVVM中的ViewModel是完全不同的概念,后者不僅包括呈現在View中的數據,也包括數據操作行為。

 


 轉載自:http://www.cnblogs.com/wj033/p/5812938.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM