国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

C#三層架構(gòu)詳細(xì)解剖

2019-11-17 03:00:51
字體:
供稿:網(wǎng)友

C#三層架構(gòu)詳細(xì)解剖

深入淺出C#三層架構(gòu)(轉(zhuǎn))

C的三層架構(gòu) - 枯草傾心 - 枯草傾心

本文用一個示例來介紹如何建設(shè)一個三層架構(gòu)的項(xiàng)目,并說明項(xiàng)目中各個文件所處的層次與作用。寫本文的目的,不是為了說明自己的這個方法有多對,而是希望給那些初學(xué)三層架構(gòu)卻不知從何入手的朋友提供一點(diǎn)幫助。因?yàn)榫W(wǎng)上的文章,大多是注重理論的介紹,而忽略了具體的實(shí)踐應(yīng)用,或者有示例但講得不透徹。導(dǎo)致看了之后,理論上又學(xué)習(xí)了一遍,但還是不知道代碼怎么寫。所以想從這個方面入手寫一下,讓從來沒做過三層架構(gòu)的初學(xué)者也能照貓畫虎,寫出代碼來。文中的代碼是偽代碼,僅用來闡明思路。 正文: 一提三層架構(gòu),大家都知道是表現(xiàn)層(UI),業(yè)務(wù)邏輯層(BLL)和數(shù)據(jù)訪問層(DAL),而且每層如何細(xì)分也都有很多的方法。但具體代碼怎么寫,到底那些文件算在哪一層,卻是模模糊糊的。下面用一個簡單的例子來帶領(lǐng)大家實(shí)戰(zhàn)三層架構(gòu)的項(xiàng)目,這個例子只有一個功能,就是用戶的簡單管理。 首先建立一個空白解決方案,添加如下項(xiàng)目及文件1、添加asp.net Web application項(xiàng)目,命名為UI,新建Web Form類型文件User.aspx(含User.aspx.cs)2、添加ClassLibrary項(xiàng)目,命名為BLL,新建Class類型文件UserBLL.cs3、添加ClassLibrary項(xiàng)目,命名為DAL,新建Class類型文件UserDAL.cs。添加SQLHelper引用。(這個是微軟的數(shù)據(jù)訪問類,也可以不用,直接編寫所有的數(shù)據(jù)訪問代碼。我一般用自己寫的數(shù)據(jù)訪問類DataaccessHelper)。4、添加ClassLibrary項(xiàng)目,命名為Model,新建Class類型文件UserModel.cs5、添加ClassLibrary項(xiàng)目,命名為IDAL,新建Interface類型文件IUserDAL.cs6、添加ClassLibrary項(xiàng)目,命名為ClassFactory相信大家已經(jīng)看出來了,這個和Petshop的示例沒什么區(qū)別,而且更簡單,因?yàn)樵谙乱彩峭ㄟ^Petshop學(xué)習(xí)三層架構(gòu)的。但一些朋友對于這幾個項(xiàng)目所處的層次,以及它們之間的關(guān)系,可能比較模糊,這里逐個說明一下:1、User.aspx和User.aspx.cs這兩個文件(以及文件所屬的項(xiàng)目,下面也是如此,不再重復(fù)強(qiáng)調(diào)了)都屬于表現(xiàn)層部分。User.aspx比較好理解,因?yàn)樗褪秋@示頁面了。User.aspx.cs有些人覺得不應(yīng)該算,而是要劃到業(yè)務(wù)邏輯層中去。如果不做分層的話,那么讓User.aspx.cs來處理業(yè)務(wù)邏輯,甚至操作數(shù)據(jù)庫都沒什么問題,但是做分層的話,這樣就不應(yīng)該了。在分層結(jié)構(gòu)中,User.aspx.cs僅應(yīng)該處理與顯示有關(guān)的內(nèi)容,其它部分都不應(yīng)該涉及。舉例:我們實(shí)現(xiàn)用列表方式顯示用戶的功能,那么提取信息的工作是由BLL來做的,UI(本例中是User.aspx.cs)調(diào)用BLL得到UserInfo后,通過代碼綁定到User.aspx的數(shù)據(jù)控件上,就實(shí)現(xiàn)了列表的顯示。在此過程中User.aspx.cs對UI沒有起到什么作用,僅是用來傳遞數(shù)據(jù),而且因?yàn)閷?shí)際編碼中大部分情況都是如此的實(shí)現(xiàn),所以使有些人覺得User.aspx.cs不應(yīng)該算UI,而應(yīng)該并入BLL負(fù)責(zé)邏輯處理。繼續(xù)往下看,這時提出了一個新需求,要求在每個用戶的前面加一個圖標(biāo),生動地表現(xiàn)出用戶的性別,而且不滿18歲的用兒童圖標(biāo)表示。這個需求的實(shí)現(xiàn),就輪到User.aspx.cs來做了,這種情況下User.aspx.cs才算有了真正的用途。2NewBLL.cs添加如下方法:public IList<UserInfo> GetUsers():返回所有的用戶信息列表public UserInfo GetUser(int UserId):返回指定用戶的詳細(xì)信息public bool AddUser(UserInfo User):新增用戶信息public bool ChangeUser(UserInfo User):更新用戶信息public void RemoveUser(int UserId):移除用戶信息此文件就屬于業(yè)務(wù)邏輯層了,專門用來處理與業(yè)務(wù)邏輯有關(guān)的操作。可能有很多人覺得這一層唯一的用途,就是把表現(xiàn)層傳過來的數(shù)據(jù)轉(zhuǎn)發(fā)給數(shù)據(jù)層。這種情況確實(shí)很多,但這只能說明項(xiàng)目比較簡單,或者項(xiàng)目本身與業(yè)務(wù)的關(guān)系結(jié)合的不緊密(比如當(dāng)前比較流行的MIS),所以造成業(yè)務(wù)層無事可做,只起到了一個轉(zhuǎn)發(fā)的作用。但這不代表業(yè)務(wù)層可有可無,隨著項(xiàng)目的增大,或者業(yè)務(wù)關(guān)系比較多,業(yè)務(wù)層就會體現(xiàn)出它的作用來了。此處最可能造成錯誤的,就是把數(shù)據(jù)操作代碼劃在了業(yè)務(wù)邏輯層,而把數(shù)據(jù)庫作為了數(shù)據(jù)訪問層。舉例:有些朋友感覺BLL層意義不大,只是將DAL的數(shù)據(jù)提上來就轉(zhuǎn)發(fā)給了UI,而未作任何處理。看一下這個例子BLL層SelectUser(UserInfo userInfo)根據(jù)傳入的username或email得到用戶詳細(xì)信息。IsExist(UserInfo userInfo)判斷指定的username或email是否存在。然后DAL也相應(yīng)提供方法共BLL調(diào)用SelectUser(UserInfo userInfo)IsExist(UserInfo userInfo)這樣BLL確實(shí)只起到了一個傳遞的作用。但如果這樣做:BLL.IsExist(Userinfo userinfo){UerInfo user = DAL.SelectUser(User); return (userInfo.Id != null);}那么DAL就無需實(shí)現(xiàn)IsExist()方法了,BLL中也就有了邏輯處理的代碼。3UserModel.cs實(shí)體類,這個東西,大家可能覺得不好分層。包括我以前在內(nèi),是這樣理解的:UIßàModelßàBLLßàModelßàDAL,如此則認(rèn)為Model在各層之間起到了一個數(shù)據(jù)傳輸?shù)臉蛄鹤饔谩2贿^在這里,我們不是把事情想簡單,而是想復(fù)雜了。Model是什么?它什么也不是!它在三層架構(gòu)中是可有可無的。它其實(shí)就是面向?qū)ο缶幊讨凶罨镜臇|西:類。一個桌子是一個類,一條新聞也是一個類,int、string、doublie等也是類,它僅僅是一個類而已。這樣,Model在三層架構(gòu)中的位置,和int,string等變量的地位就一樣了,沒有其它的目的,僅用于數(shù)據(jù)的存儲而已,只不過它存儲的是復(fù)雜的數(shù)據(jù)。所以如果你的項(xiàng)目中對象都非常簡單,那么不用Model而直接傳遞多個參數(shù)也能做成三層架構(gòu)。那為什么還要有Model呢,它的好處是什么呢。下面是思考一個問題時想到的,插在這里:Model在各層參數(shù)傳遞時到底能起到做大的作用?在各層間傳遞參數(shù)時,可以這樣:AddUser(userId,userName,userPassWord,&hellip;,)也可以這樣:AddUser(userInfo)這兩種方法那個好呢。一目了然,肯定是第二種要好很多。什么時候用普通變量類型(int,string,guid,double)在各層之間傳遞參數(shù),什么使用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這三個參數(shù)的四種組合模式。UserId其實(shí)也可以合并到user中,但項(xiàng)目中其它BLL都實(shí)現(xiàn)了帶有id參數(shù)的接口,所以這里也保留這一項(xiàng)。傳入了userInfo,那如何處理呢,這個就需要按照先后的順序了,有具體代碼決定。這里按這個順序處理首先看是否同時具有username和password,然后看是否同時具有email和password,然后看是否有username,然后看是否有email。依次處理。這樣,如果以后增加一個新內(nèi)容,會員卡(number),則無需更改接口,只要在DAL的代碼中增加對number的支持就行,然后前臺增加會員卡一項(xiàng)內(nèi)容的表現(xiàn)與處理即可。4UserDAL.cspublic IList<UserInfo> SelectUsers():返回所有的用戶信息列表(返回的一個泛型列表,可以進(jìn)行序列化等操作)public UserInfo SelectUser(int UserId):返回指定用戶的相信信息(通過ID,返回實(shí)體類的實(shí)例相關(guān)信息)public bool InsertUser(UserInfo User):新增用戶信息(不同于Select,因?yàn)樵黾雍透率遣粫祷貙?shí)體數(shù)據(jù),只返回一個bool值表明操作是否成功)public bool UpdateUser(UserInfo User):更新用戶信息(同上)public void DeleteUser(int UserId):移除用戶信息(這個)很多人最鬧不清的就是數(shù)據(jù)訪問層,到底那部分才算數(shù)據(jù)訪問層呢?有些認(rèn)為數(shù)據(jù)庫就是數(shù)據(jù)訪問層,這是對定義沒有搞清楚,DAL是數(shù)據(jù)訪問層而不是數(shù)據(jù)存儲層,因此數(shù)據(jù)庫不可能是這一層的。也有的把SQLHelper(或其同類作用的組件)作為數(shù)據(jù)訪問層,它又是一個可有可無的東西,SQLHelper的作用是減少DAL層的重復(fù)性編碼,提高編碼效率,因此如果我習(xí)慣在乎效率或使用一個非數(shù)據(jù)庫的數(shù)據(jù)源時,可以丟棄SQLHelper,一個可以隨意棄置的部分,又怎么能成為三層架構(gòu)中的一層呢。可以這樣定義:與數(shù)據(jù)源操作有關(guān)的代碼,就應(yīng)該放在數(shù)據(jù)訪問層中,屬于數(shù)據(jù)訪問層5IUserDAL數(shù)據(jù)訪問層接口,這又是一個可有可無的東西,因?yàn)镻etshop中帶了它和ClassFactory類工廠,所以有些項(xiàng)目不論需不需要支持多數(shù)據(jù)源,都把這兩個東西做了進(jìn)來,有的甚至不建ClassFactory而只建了IDAL,然后“IUserDAL iUserDal = new UserDAL();”,不知意義何在。這就完全是畫虎不成反類犬了。許多人在這里有一個誤解,那就是以為存在這樣的關(guān)系:BLLßàIDALßàDAL,認(rèn)為IDAL起到了BLL和DAL之間的橋梁作用,BLL是通過IDAL來調(diào)用DAL的。但實(shí)際是即使你如此編碼:“IUserDAL iUserDal = ClassFacotry.CreateUserDAL();”,那么在執(zhí)行“iUserDal.SelectUsers()”時,其實(shí)還是執(zhí)行的UserDAL實(shí)例,而不是IUserDAL實(shí)例,所以IDAL在三層中的位置是與DAL平級的關(guān)系。 通過上面的介紹,基本上將三層架構(gòu)的層次結(jié)構(gòu)說明了。其實(shí),本人有一個判斷三層架構(gòu)是否標(biāo)準(zhǔn)的方法,那就是將三層中的任意一層完全替換,都不會對其它兩層造成影響,這樣的構(gòu)造基本就符合三層標(biāo)準(zhǔn)了(雖然實(shí)現(xiàn)起來比較難^_^)。例如如果將項(xiàng)目從B/S改為C/S(或相反),那么除了UI以外,BLL與DAL都不用改動;或者將SQLServer改為Oracle,只需替換SQLServerDAL到OracleDAL,無需其它操作等等。總結(jié):不要因?yàn)槟硞€層對你來說沒用,或者實(shí)現(xiàn)起來特別簡單,就認(rèn)為它沒有必要,或者摒棄它,或者挪作它用。只要進(jìn)行了分層,不管是幾層,每一層都要有明確的目的和功能實(shí)現(xiàn),而不要被實(shí)際過程所左右,造成同一類文件位于不同層的情況發(fā)生。也不要出現(xiàn)同一層實(shí)現(xiàn)了不同的功能的情況發(fā)生。

我自己補(bǔ)充點(diǎn)代碼讓大家看看三層式如何調(diào)用的,(一般我從DAL開始寫,其實(shí)我覺得更應(yīng)該從BLL層開始寫,那樣才更加明了你的項(xiàng)目的需求是哪些,BBL本來就是業(yè)務(wù)邏輯層嘛)

第一步:DAL層的一個方法:(注意看注釋)

先給點(diǎn)SQLHelpher的方法給大家看看先:(注意參數(shù)和返回類型,增刪改都是返回影響行數(shù))

/// <summary>        /// 執(zhí)行無參SQL語句,并返回執(zhí)行行數(shù)        /// </summary>        public static int GetScalar(string safeSql)        {            SqlCommand cmd = new SqlCommand(safeSql, Connection);            int result = Convert.ToInt32(cmd.ExecuteScalar());            return result;        }        /// <summary>        /// 執(zhí)行有參SQL語句,并返回執(zhí)行行數(shù)        /// </summary>        public static int GetScalar(string sql, params SqlParameter[] values)        {            SqlCommand cmd = new SqlCommand(sql, Connection);            cmd.Parameters.AddRange(values);            int result = Convert.ToInt32(cmd.ExecuteScalar());            return result;        }        /// <summary>        /// 執(zhí)行無參SQL語句,并返SqlDataReader        /// </summary>        public static SqlDataReader GetReader(string safeSql)        {            SqlCommand cmd = new SqlCommand(safeSql, Connection);            SqlDataReader reader = cmd.ExecuteReader();            return reader;        }

再給個Model層的實(shí)體類:

[Serializable]   public class RoomType   {       PRotected int typeId;       protected string typeName = String.Empty;       public RoomType()       {       }             public int TypeId       {           get { return typeId; }           set { typeId = value; }       }       public string TypeName       {           get { return typeName; }           set { typeName = value; }       }}

第二步:.看看BLL如何調(diào)用DAL的方法(如上所說,DAL只做數(shù)據(jù)查詢,BLL才涉及到邏輯判斷和推理)

 /// <summary>       /// 根據(jù)類型ID的房間信息集合       /// </summary>       public static IList<Room> GetAllRoomsByTypeId(int roomTypeId)       {           try           {               return RoomService.GetAllRoomsByTypeId(roomTypeId);           }           catch (Exception ex)           {               throw new Exception(ex.ToString());           }       }       /// <summary>       /// 得到房間信息集合       /// </summary>       public static IList<Room> GetAllRooms()       {           try           {               return RoomService.GetAllRooms();           }           catch (Exception ex)           {               throw new Exception(ex.ToString());           }       }       /// <summary>       /// 根據(jù)房間ID得到客房信息實(shí)體對象       /// </summary>       public static Room GetRoomByRoomId(int roomId)       {           try           {               return RoomService.GetRoomByRoomId(roomId);           }           catch (Exception ex)           {               throw new Exception(ex.ToString());           }       }

第三步:Web層(UI) ,只是把BLL層得到的數(shù)據(jù)給綁定到Web控件就ok了,只做頁面布局和數(shù)據(jù)綁定相關(guān)的事情(如監(jiān)聽按鈕事件,設(shè)置Style的風(fēng)格,其實(shí)完全可以結(jié)合DOM

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 镇安县| 三江| 郑州市| 自治县| 丹棱县| 清涧县| 仙桃市| 安达市| 天水市| 社旗县| 织金县| 娄烦县| 额济纳旗| 乐安县| 文昌市| 资兴市| 万安县| 灌云县| 吕梁市| 确山县| 本溪| 孟津县| 三原县| 达日县| 东乡县| 祁阳县| 广昌县| 肥东县| 定南县| 全州县| 凭祥市| 茶陵县| 淳化县| 黄梅县| 海城市| 兴海县| 墨脱县| 恭城| 台东市| 徐州市| 清水县|