本文不是從理論的角度來探討三層架構
而是用一個示例來介紹如何建設一個三層架構的項目
並說明項目中各個文件所處的層次與作用
寫本文的目的
不是為了說明自己的這個方法有多對
別人的肯定不對
而是希望給那些初學三層架構卻不知從何入手的朋友提供一點幫助
因為網上的文章
大多是注重理論的介紹
而忽略了具體的實踐應用
或者有示例但講得不透徹
導致看了之後
理論上又學習了一遍
但還是不知道代碼怎麼寫
所以想從這個方面入手寫一下
讓從來沒做過三層架構的初學者也能照貓畫虎
寫出代碼來
文章表述的是筆者個人對三層架構的認識
肯定有許多不足的地方
歡迎大家指正
小弟也會根據反饋來修改這篇文章
文中的代碼是偽代碼
僅用來闡明思路
一提三層架構
大家都知道是表現層(UI)
業務邏輯層(BLL)和數據訪問層(DAL)
而且每層如何細分也都有很多的方法
但具體代碼怎麼寫
到底那些文件算在哪一層
卻是模模糊糊的
下面用一個簡單的例子來帶領大家實戰三層架構的項目
這個例子只有一個功能
就是用戶的簡單管理
首先建立一個空白解決方案添加如下項目及文件
添加ASP
NET Web Application項目
命名為UI
新建Web Form類型文件User
aspx(含User
aspx
cs)
添加ClassLibrary項目
命名為BLL
新建Class類型文件UserBLL
cs
添加ClassLibrary項目
命名為DAL
新建Class類型文件UserDAL
cs
添加SQLHelper引用
(這個是微軟的數據訪問類
也可以不用
直接編寫所有的數據訪問代碼
我一般用自己寫的數據訪問類DataAccessHelper )
添加ClassLibrary項目
命名為Model
新建Class類型文件UserModel
cs
添加ClassLibrary項目
命名為IDAL
新建Interface類型文件IUserDAL
cs
添加ClassLibrary項目
命名為ClassFactory
相信大家已經看出來了
這個和Petshop的示例沒什麼區別
而且更簡單
因為在下也是通過Petshop學習三層架構的
但一些朋友對於這幾個項目所處的層次
以及它們之間的關系
可能比較模糊
這裡逐個說明一下
Useraspx和Useraspxcs
這兩個文件(以及文件所屬的項目
下面也是如此
不再重復強調了)都屬於表現層部分
User
aspx比較好理解
因為它就是顯示頁面了
User
aspx
cs有些人覺得不應該算
而是要劃到業務邏輯層中去
如果不做分層的話
那麼讓User
aspx
cs來處理業務邏輯
甚至操作數據庫都沒什麼問題
但是做分層的話
這樣就不應該了
在分層結構中
User
aspx
cs僅應該處理與顯示有關的內容
其它部分都不應該涉及
舉例
我們實現用列表方式顯示用戶的功能
那麼提取信息的工作是由BLL來做的
UI(本例中是User
aspx
cs)調用BLL得到UserInfo後
通過代碼綁定到User
aspx的數據控件上
就實現了列表的顯示
在此過程中User
aspx
cs對UI沒有起到什麼作用
僅是用來傳遞數據
而且因為實際編碼中大部分情況都是如此的實現
所以使有些人覺得User
aspx
cs不應該算UI
而應該並入BLL負責邏輯處理
繼續往下看
這時提出了一個新需求
要求在每個用戶的前面加一個圖標
生動地表現出用戶的性別
而且不滿
歲的用兒童圖標表示
這個需求的實現
就輪到User
aspx
cs來做了
這種情況下User
aspx
cs才算有了真正的用途
NewBLLcs
添加如下方法
public IList<UserInfo> GetUsers()
返回所有的用戶信息列表
public UserInfo GetUser(int UserId)
返回指定用戶的詳細信息
public bool AddUser(UserInfo User)
新增用戶信息
public bool ChangeUser(UserInfo User)
更新用戶信息
public void RemoveUser(int UserId)
移除用戶信息
此文件就屬於業務邏輯層了
專門用來處理與業務邏輯有關的操作
可能有很多人覺得這一層唯一的用途
就是把表現層傳過來的數據轉發給數據層
這種情況確實很多
但這只能說明項目比較簡單
或者項目本身與業務的關系結合的不緊密(比如當前比較流行的MIS)
所以造成業務層無事可做
只起到了一個轉發的作用
但這不代表業務層可有可無
隨著項目的增大
或者業務關系比較多
業務層就會體現出它的作用來了
此處最可能造成錯誤的
就是把數據操作代碼劃在了業務邏輯層
而把數據庫作為了數據訪問層
舉例
有些朋友感覺BLL層意義不大
只是將DAL的數據提上來就轉發給了UI
而未作任何處理
看一下這個例子
BLL層
SelectUser(UserInfo userInfo)根據傳入的username或email得到用戶詳細信息
IsExist(UserInfo userInfo)判斷指定的username或email是否存在
然後DAL也相應提供方法共BLL調用
SelectUser(UserInfo userInfo)
IsExist(UserInfo userInfo)
這樣BLL確實只起到了一個傳遞的作用
但如果這樣做
BLL
IsExist(Userinfo userinfo)
{
UerInfo user = DAL
SelectUser(User)
return (userInfo
Id != null)
}
那麼DAL就無需實現IsExist()方法了
BLL中也就有了邏輯處理的代碼
UserModelcs
實體類
這個東西
大家可能覺得不好分層
包括我以前在內
是這樣理解的
UI?àModel?àBLL?àModel?àDAL
如此則認為Model在各層之間起到了一個數據傳輸的橋梁作用
不過在這裡
我們不是把事情想簡單
而是想復雜了
Model是什麼?它什麼也不是!它在三層架構中是可有可無的
它其實就是面向對象編程中最基本的東西
類
一個桌子是一個類
一條新聞也是一個類
int
string
doublie等也是類
它僅僅是一個類而已
這樣
Model在三層架構中的位置
和int
string等變量的地位就一樣了
沒有其它的目的
僅用於數據的存儲而已
只不過它存儲的是復雜的數據
所以如果你的項目中對象都非常簡單
那麼不用Model而直接傳遞多個參數也能做成三層架構
那為什麼還要有Model呢
它的好處是什麼呢
下面是思考一個問題時想到的
插在這裡
Model在各層參數傳遞時到底能起到做大的作用?
在各層間傳遞參數時
可以這樣
AddUser(userId
userName
userPassword
…
)
也可以這樣
AddUser(userInfo)
這兩種方法那個好呢
一目了然
肯定是第二種要好很多
什麼時候用普通變量類型(int
string
guid
double)在各層之間傳遞參數
什麼使用Model傳遞?下面幾個方法
SelectUser(int UserId)
SelectUserByName(string username)
SelectUserByName(string username
string password)
SelectUserByEmail(string email)
SelectUserByEmail(string email
string password)
可以概括為
SelectUser(userId)
SelectUser(user)
這裡用user這個Model對象囊括了username
password
email這三個參數的四種組合模式
UserId其實也可以合並到user中
但項目中其它BLL都實現了帶有id參數的接口
所以這裡也保留這一項
傳入了userInfo
那如何處理呢
這個就需要按照先後的順序了
有具體代碼決定
這裡按這個順序處理
首先看是否同時具有username和password
然後看是否同時具有email和password
然後看是否有username
然後看是否有email
依次處理
這樣
如果以後增加一個新內容
會員卡(number)
則無需更改接口
只要在DAL的代碼中增加對number的支持就行
然後前台增加會員卡一項內容的表現與處理即可
UserDALcs
public IList<UserInfo> SelectUsers()
返回所有的用戶信息列表
public UserInfo SelectUser(int UserId)
返回指定用戶的相信信息
public bool InsertUser(UserInfo User)
新增用戶信息
public bool UpdateUser(UserInfo User)
更新用戶信息
public void DeleteUser(int UserId)
移除用戶信息
很多人最鬧不清的就是數據訪問層
到底那部分才算數據訪問層呢?有些認為數據庫就是數據訪問層
這是對定義沒有搞清楚
DAL是數據訪問層而不是數據存儲層
因此數據庫不可能是這一層的
也有的把SQLHelper(或其同類作用的組件)作為數據訪問層
它又是一個可有可無的東西
SQLHelper的作用是減少重復性編碼
提高編碼效率
因此如果我習慣在乎效率或使用一個非數據庫的數據源時
可以丟棄SQLHelper
一個可以隨意棄置的部分
又怎麼能成為三層架構中的一層呢
可以這樣定義
與數據源操作有關的代碼
就應該放在數據訪問層中
屬於數據訪問層
IUserDAL
數據訪問層接口
這又是一個可有可無的東西
因為Petshop中帶了它和ClassFactory類工廠
所以有些項目不論需不需要支持多數據源
都把這兩個東西做了進來
有的甚至不建ClassFactory而只建了IDAL
然後
IUserDAL iUserDal = new UserDAL()
不知意義何在
這就完全是畫虎不成反類犬了
許多人在這裡有一個誤解
那就是以為存在這樣的關系
BLL?àIDAL?àDAL
認為IDAL起到了BLL和DAL之間的橋梁作用
BLL是通過IDAL來調用DAL的
但實際是即使你如此編碼
IUserDAL iUserDal = ClassFacotry
CreateUserDAL()
那麼在執行
iUserDal
SelectUsers()
時
其實還是執行的UserDAL實例
而不是IUserDAL實例
所以IDAL在三層中的位置是與DAL平級的關系
通過上面的介紹
基本上將三層架構的層次結構說明了
其實
本人有一個判斷三層架構是否標准的方法
那就是將三層中的任意一層完全替換
都不會對其它兩層造成影響
這樣的構造基本就符合三層標准了(雖然實現起來比較難^_^)
例如如果將項目從B/S改為C/S(或相反)
那麼除了UI以外
BLL與DAL都不用改動
或者將SQLServer改為Oracle
只需替換SQLServerDAL到OracleDAL
無需其它操作等等
本來想在文中加入一些具體的代碼的
但感覺不是很必要
如果大家覺得需要的話
我再補充吧
總結
不要因為某個層對你來說沒用
或者實現起來特別簡單
就認為它沒有必要
或者摒棄它
或者挪作它用
只要進行了分層
不管是幾層
每一層都要有明確的目的和功能實現
而不要被實際過程所左右
造成同一類文件位於不同層的情況發生
也不要出現同一層實現了不同的功能的情況發生
From:http://tw.wingwit.com/Article/program/net/201311/13706.html