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



1.1、 規則
- 最關鍵的,UI層只能作為一個外殼,不能包含任何業務邏輯(BizLogic)的處理過程。只有少量(或者沒有)SQL語句或者存儲過程的調用,並且這些語句保證不會修改數據。
- 設計時應該從BLL出發,而不是UI出發。BLL層在API上應該實現所有BizLogic(以面向對象的方式)。如果把UILayer拿掉,項目還能在Interface/API的層次上提供所有功能)。
- 不管數據層是一個簡單的SqlHelper也好,還是帶有Mapping過的Classes也好,應該在一定的抽象程度上做到系統無關(DAL可以移植到其他類似環境的項目)。
- 不管使用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中的控制器,內里封裝了通訊,容易變成大而全 的高度耦合的集中器。
- 控制器中寫業務代碼
- UI邏輯可以寫在Controller中,而業務邏輯應該在Model里,Controller只是去調用它們。
-
控制器變得依賴信息數據中心或數據庫,對象將間接地通過控制器的action耦合在一起
- 可以通過引入IOC容器來解決
2.2、 總結
MVC最早的定義畢竟是79年提出的,到現在GUI編程環境,業務復雜程度都有了很大改變。當采用MVC模式設計UI應用時,一般會根據開發框架的特點來對Model,View和Contoller設置一個明確的界限,同時為它們之間的交互制定一個更加嚴格的規則。
3、 MVC變體
在軟件發展歷程中出現了一些MVC變體,它們遵循定義在MVC中的基本原則,但對三元素直接的交互制定了更為嚴格的規范。
3.1、 MVP
- MVP適用於基於事件驅動的應用框架中,如Asp.net Web Forms 和Windows Forms應用。
- MVP中嚴格禁止View和Model間的直接交互,必需通過Presenter來完成。Model的獨立性得到了真正的體現,它不僅僅與可視化元素的呈現(View)無關,與UI處理邏輯也無關。使用MVP的應用是用戶驅動而不是Model驅動,所以Model不需要主動通知view。
- 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里的接口盡量只包含方法,且是無返回值的方法(單向傳遞消息)。
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();
}
}
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