生活随笔
收集整理的這篇文章主要介紹了
抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
分層思想的一個(gè)核心就是部件化,各個(gè)層之間是相互獨(dú)立的,每一層可以隨便抽取換成一個(gè)其他語言的版本,但只要與相應(yīng)的接口吻合就行。
我用的三層架構(gòu)大致是這樣的,基本的三層就不說了,然后分別為業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層定義一個(gè)接口,由具體的那個(gè)層來實(shí)現(xiàn),問題產(chǎn)生了,由誰來指定程序使用哪個(gè)具體的對(duì)象來實(shí)現(xiàn)相應(yīng)接口?
為解決這個(gè)問題,我應(yīng)用的是抽象工廠模式。分別為業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層添加一個(gè)抽象工廠。具體架構(gòu)還是看下圖吧。
這里的Utility是一個(gè)工具類,在下文中會(huì)提到。
學(xué)過設(shè)計(jì)模式的人都應(yīng)該聽過反射技術(shù),但是一個(gè)系統(tǒng)中用到的類很多,需要對(duì)每一個(gè)類進(jìn)行實(shí)例化,如果僅利用抽象工廠+反射模式,重復(fù)的代碼比較多,如果哪一天整個(gè)DAL層發(fā)生變更,那么就要在代碼中修改每一個(gè)用到的地方,不僅不容易維護(hù),而且還很容易出錯(cuò),未解決這個(gè)問題,對(duì)程序作了一個(gè)優(yōu)化——用到依賴注入。還是看看代碼吧。
1、先看看依賴注入的容器:這里我把這個(gè)注入容器放到了工具類中,剛開始學(xué)習(xí)設(shè)計(jì)模式,不知道是否合理,歡迎高手們指點(diǎn)。
[vb]?view plaincopy
Imports?System.Configuration?? Imports?System.Reflection?? Public?Class?DependencyInjector?? ?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?GetDALObject(ByVal?className?As?String)?As?Object?? ????????Dim?dal?As?Object?? ????????Dim?dalName?As?String?? ????????Dim?fullClassName?As?String?? ????????Dim?dalObj?As?Object?? ?? ?????????? ????????dal?=?System.Configuration.ConfigurationManager.AppSettings("DAL")?? ?? ?????????? ????????dalName?=?dal.ToString?? ?? ?????????? ????????fullClassName?=?dalName?+?"."?+?className?? ?????????? ????????dalObj?=?Assembly.Load(dalName).CreateInstance(fullClassName)?? ?????????? ????????Return?dalObj?? ?? ????End?Function?? ?? ?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?GetBLLObject(ByVal?className?As?String)?As?Object?? ?? ????????Dim?bll?As?Object?? ????????Dim?bllName?As?String?? ????????Dim?bllObj?As?Object?? ????????Dim?fullClassName?As?String?? ?? ?????????? ????????bll?=?System.Configuration.ConfigurationManager.AppSettings("BLL")?? ????????bllName?=?bll.ToString?? ?? ????????fullClassName?=?bllName?+?"."?+?className?? ?? ?????????? ????????bllObj?=?Assembly.Load(bllName).CreateInstance(fullClassName)?? ?? ????????Return?bllObj?? ?? ????End?Function?? End?Class??
2、相關(guān)配置文件:
[html]?view plaincopy
<appSettings>?? ????<add?key="connStr"??value="Persist?Security?Info=true;Data?Source=*****;Initial?Catalog=Charge_Sys_SelfDesign;User?ID=sa;PWD=****;"?/>?? ????<add?key="DAL"??value="DAL"?/>?? ????<add?key="BLL"??value="BLL"?/>?????? ??</appSettings>??
3、業(yè)務(wù)邏輯層工廠:這里以在工廠中生產(chǎn)一個(gè)UserBLL類為例,在工廠中添加CreateUserBLL()方法,理論上講,業(yè)務(wù)邏輯層有多少個(gè)類在此工廠中就要有多少個(gè)相應(yīng)的方法,但是針對(duì)不同語言寫的或者是不同的程序員用同一種語言寫的同一層的代碼(但都實(shí)現(xiàn)了程序指定的接口),我們?cè)诮o類起名字的時(shí)候,只要用相同的類名就可以通過僅修改配置文件,達(dá)到換層的目的,而無需在工廠中改動(dòng)任何代碼。比如說,我現(xiàn)在要把DAL層換成AccessDAL,那么僅需要做如下修改即可。
[html]?view plaincopy
<add?key="DAL"??value="AccessDAL"?/>??
這就是分層的好處,當(dāng)然也是面向?qū)ο笏枷氲膬?yōu)勢(shì)了。
上面主要是解釋了一下配置文件,來看看業(yè)務(wù)邏輯工廠代碼:
[vb]?view plaincopy
Imports?IBLL?? Imports?Utility?? Imports?System.Configuration?? Imports?System.Reflection?? Imports?System.Windows.Forms?? Public?Class?CreateBLL?? ?? ????Private?dependecy?As?New?Utility.DependencyInjector?? ?? ?????? ?????? ?????? ?????? ?????? ????Public?Function?CreateUserBLL()?As?IBLL.IUserBLL?? ????????Try?? ?????????????? ?????????????? ?????????????? ????????????Return?CType(dependecy.GetBLLObject("UserBLL"),?IBLL.IUserBLL)?? ????????Catch?ex?As?Exception?? ????????????MsgBox(ex.Message)?? ????????????Return?Nothing?? ????????End?Try?? ????End?Function?? End?Class??
4、數(shù)據(jù)訪問層工廠代碼類似:
[vb]?view plaincopy
Imports?Utility?? Imports?System.Configuration?? Imports?System.Reflection?? Imports?IDAL?? Imports?System.Windows.Forms?? ?? Public?Class?CreateDAL?? ?? ????Private?dependency?As?New?Utility.DependencyInjector?? ?? ?????? ?????? ?????? ?????? ?????? ????Public?Function?CreateUserDAL()?As?IDAL.IUserDAL?? ????????Try?? ?????????????? ????????????Return?CType(dependency.GetDALObject("UserDAL"),?IDAL.IUserDAL)?? ????????Catch?ex?As?Exception?? ????????????MessageBox.Show(ex.Message)?? ????????????Return?Nothing?? ????????End?Try?? ?? ????End?Function?? End?Class??
5、業(yè)務(wù)邏輯層接口代碼比較簡單,只需要定義一些相關(guān)接口方法即可,但是這里面體現(xiàn)了系統(tǒng)的架構(gòu),看似代碼簡單,實(shí)則反應(yīng)程序員的架構(gòu)水平。
[vb]?view plaincopy
Public?Interface?IUserBLL?? ?? ?????? ????Function?LogIn(ByVal?modelUser?As?Model.User)?As?String?? ?? End?Interface??
6、數(shù)據(jù)訪問層接口:
[vb]?view plaincopy
Public?Interface?IUserDAL?? ?? ?????? ????Function?GetID(ByVal?modelUser?As?Model.User)?As?String?? ?????? ????Function?GetPwd(ByVal?modelUser?As?Model.User)?As?String?? ?????? ????Function?GetLevel(ByVal?modelUser?As?Model.User)?As?String?? ?? End?Interface??
7、業(yè)務(wù)邏輯層:
[vb]?view plaincopy
Imports?DALFactory?? Imports?IBLL?? Imports?IDAL?? Imports?Model?? Imports?System.Data.SqlClient?? Imports?System.Collections.Generic?? Public?Class?UserBLL?? ????Implements?IBLL.IUserBLL?? ????Private?dalFactory?As?New?DALFactory.CreateDAL?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?LogIn(ByVal?modelUser?As?Model.User)?As?String?Implements?IBLL.IUserBLL.LogIn?? ????????Dim?userLevel?As?String?? ????????Try?? ????????????If?dalFactory.CreateUserDAL.GetID(modelUser)?=?""?Then?? ????????????????MsgBox("用戶名錯(cuò)誤!")?? ????????????????Return?Nothing?? ????????????????Exit?Function?? ????????????End?If?? ????????????If?dalFactory.CreateUserDAL.GetPwd(modelUser)?=?""?Then?? ????????????????MsgBox("密碼名錯(cuò)誤!")?? ????????????????Return?Nothing?? ????????????????Exit?Function?? ????????????End?If?? ?? ?? ?????????????? ????????????userLevel?=?dalFactory.CreateUserDAL.GetLevel(modelUser)?? ?? ?? ????????Catch?ex?As?Exception?? ????????????Return?Nothing?? ????????End?Try?? ????????Return?userLevel?? ????End?Function?? End?Class??
?
8、數(shù)據(jù)訪問層:
[vb]?view plaincopy
Imports?System.Data.SqlClient?? Imports?Utility?? Imports?System.Windows.Forms?? ?? Public?Class?UserDAL?? ?????? ????Implements?IDAL.IUserDAL?? ????Private?sqlHelp?As?New?Utility.SQLServerDALHelp?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?GetID(ByVal?modelUser?As?Model.User)?As?String?Implements?IDAL.IUserDAL.GetID?? ????????Dim?User_ID?As?String?? ????????Dim?conn?As?New?SqlConnection(sqlHelp.connStr)?? ????????Dim?spName?As?String?? ????????spName?=?"proc_GetUserID"?? ????????Dim?cmd?As?New?SqlCommand(spName,?conn)?? ????????cmd.CommandType?=?CommandType.StoredProcedure?? ????????Dim?Param?As?SqlParameter?? ????????Param?=?New?SqlParameter("@User_ID",?SqlDbType.VarChar)?? ????????Param.Value?=?modelUser.User_ID?? ????????cmd.Parameters.Add(Param)?? ?? ????????Try?? ????????????conn.Open()?? ????????????User_ID?=?cmd.ExecuteScalar.ToString?? ????????????Return?User_ID?? ????????Catch?ex?As?Exception?? ????????????MsgBox(ex.Message)?? ????????????Throw?New?Exception(ex.Message)?? ????????Finally?? ????????????conn.Close()?? ????????????cmd.Dispose()?? ????????????cmd?=?Nothing?? ????????End?Try?? ????????Return?User_ID?? ????End?Function?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?GetPwd(ByVal?modelUser?As?Model.User)?As?String?Implements?IDAL.IUserDAL.GetPwd?? ????????Dim?user_Pwd?As?String?? ????????Dim?spName?As?String?? ????????spName?=?"proc_GetUserPwd"?? ????????Dim?conn?As?New?SqlConnection(sqlHelp.connStr)?? ????????Dim?cmd?As?New?SqlCommand(spName,?conn)?? ????????cmd.CommandType?=?CommandType.StoredProcedure?? ?? ????????Dim?Param?As?SqlParameter?? ????????Param?=?New?SqlParameter("@User_Pwd",?SqlDbType.VarChar)?? ????????Param.Value?=?modelUser.User_Pwd?? ????????cmd.Parameters.Add(Param)?? ?? ????????Param?=?New?SqlParameter("@User_ID",?SqlDbType.VarChar)?? ????????Param.Value?=?modelUser.User_Pwd?? ????????cmd.Parameters.Add(Param)?? ????????Try?? ????????????conn.Open()?? ????????????user_Pwd?=?cmd.ExecuteScalar.ToString?? ????????Catch?ex?As?Exception?? ????????????MsgBox(ex.Message)?? ????????????Throw?New?Exception(ex.Message)?? ????????Finally?? ????????????conn.Close()?? ????????????cmd.Dispose()?? ????????????cmd?=?Nothing?? ????????End?Try?? ????????Return?user_Pwd?? ????End?Function?? ?????? ?????? ?????? ?????? ?????? ?????? ????Public?Function?GetLevel(ByVal?modelUser?As?Model.User)?As?String?Implements?IDAL.IUserDAL.GetLevel?? ????????Dim?User_Level?As?String?? ????????Dim?spName?As?String?? ????????spName?=?"proc_GetUserLevel"?? ????????Dim?conn?As?New?SqlConnection(sqlHelp.connStr)?? ????????Dim?cmd?As?New?SqlCommand(spName,?conn)?? ????????cmd.CommandType?=?CommandType.StoredProcedure?? ?? ????????Dim?Param?As?SqlParameter?? ????????Param?=?New?SqlParameter("@User_ID",?SqlDbType.VarChar)?? ????????Param.Value?=?modelUser.User_ID?? ????????cmd.Parameters.Add(Param)?? ????????Try?? ????????????conn.Open()?? ????????????User_Level?=?cmd.ExecuteScalar.ToString?? ????????Catch?ex?As?Exception?? ????????????MsgBox(ex.Message)?? ????????????Throw?New?Exception(ex.Message)?? ????????Finally?? ????????????conn.Close()?? ????????????cmd.Dispose()?? ????????????cmd?=?Nothing?? ????????End?Try?? ????????Return?User_Level?? ????End?Function?? End?Class??
9、總算到UI層了:注意這里還沒有添加針對(duì)用戶輸入合法性的驗(yàn)證,如,用戶名、密碼輸入是否為空,是否符合指定格式等。
[vb]?view plaincopy
Imports?Model?? Imports?IBLL?? Imports?System.Collections.Generic?? Imports?BLLFactory?? Public?Class?frmLogIn?? ?? ????Private?bllFactory?As?New?BLLFactory.CreateBLL?? ????Private?Sub?btnLogIn_Click(ByVal?sender?As?System.Object,?ByVal?e?As?System.EventArgs)?Handles?btnLogIn.Click?? ????????Dim?modelUser?As?New?Model.User?? ????????Dim?userLevel?As?String?? ?? ????????modelUser.User_ID?=?txtUserID.Text?? ????????modelUser.User_Pwd?=?txtUserPwd.Text?? ?? ?? ?????????? ????????userLevel?=?bllFactory.CreateUserBLL.LogIn(modelUser)?? ?? ?? ????????Select?Case?userLevel?? ????????????Case?"一般用戶"?? ?? ????????????Case?"操作員"?? ?? ????????????Case?"管理員"?? ????????????????frmMDIParentForm.Show()?? ?????????????? ????????????Case?Else?? ????????????????MsgBox("未知錯(cuò)誤!")?? ????????????????Exit?Sub?? ????????End?Select?? ????End?Sub?? ?? ????Private?Sub?btnExit_Click(ByVal?sender?As?System.Object,?ByVal?e?As?System.EventArgs)?Handles?btnExit.Click?? ????????txtUserID.Text?=?""?? ????????txtUserPwd.Text?=?""?? ????????Me.Close()?? ????End?Sub?? ????? End?Class??
到此為止,一個(gè)簡單的三層架構(gòu)就算實(shí)現(xiàn)了,隱約感覺設(shè)計(jì)上有些地方不合理,但說不好存在于哪些地方,希望由此路過的大牛們,多多指教,另外,這里的數(shù)據(jù)訪問層代碼冗余較多,在后續(xù)的博客中,會(huì)通過編寫一個(gè)SQLHelp來實(shí)現(xiàn)優(yōu)化,還有UML包圖也會(huì)在后續(xù)博客中天上。
最后說說我自己的感觸。
針對(duì)架構(gòu):用到了兩個(gè)抽象工廠,剛開始是將兩個(gè)工廠寫到了一層中,這層的名稱就叫Factory,而且封裝注入的類也一并放到了這層中,但是在調(diào)試程序的時(shí)候出現(xiàn)DAL層依賴循環(huán)調(diào)用錯(cuò)誤,不知道是代碼還是設(shè)計(jì)上的原因?
針對(duì)接口設(shè)計(jì):不太清楚業(yè)務(wù)邏輯層的方法設(shè)計(jì)是否合理,現(xiàn)在的一個(gè)問題就是如果用戶名或者密碼出錯(cuò)的話,并不是由UI層向用戶提供反饋信息,而是由業(yè)務(wù)邏輯層擔(dān)當(dāng)了此任務(wù),暫且就這么寫吧,估計(jì)到后面寫的多了就找到合適的方法了。
總結(jié)
以上是生活随笔為你收集整理的抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。