生活随笔
收集整理的這篇文章主要介紹了
抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
分層思想的一個核心就是部件化,各個層之間是相互獨立的,每一層可以隨便抽取換成一個其他語言的版本,但只要與相應的接口吻合就行。
我用的三層架構大致是這樣的,基本的三層就不說了,然后分別為業務邏輯層和數據訪問層定義一個接口,由具體的那個層來實現,問題產生了,由誰來指定程序使用哪個具體的對象來實現相應接口?
為解決這個問題,我應用的是抽象工廠模式。分別為業務邏輯層和數據訪問層添加一個抽象工廠。具體架構還是看下圖吧。
這里的Utility是一個工具類,在下文中會提到。
學過設計模式的人都應該聽過反射技術,但是一個系統中用到的類很多,需要對每一個類進行實例化,如果僅利用抽象工廠+反射模式,重復的代碼比較多,如果哪一天整個DAL層發生變更,那么就要在代碼中修改每一個用到的地方,不僅不容易維護,而且還很容易出錯,未解決這個問題,對程序作了一個優化——用到依賴注入。還是看看代碼吧。
1、先看看依賴注入的容器:這里我把這個注入容器放到了工具類中,剛開始學習設計模式,不知道是否合理,歡迎高手們指點。
[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、相關配置文件:
[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、業務邏輯層工廠:這里以在工廠中生產一個UserBLL類為例,在工廠中添加CreateUserBLL()方法,理論上講,業務邏輯層有多少個類在此工廠中就要有多少個相應的方法,但是針對不同語言寫的或者是不同的程序員用同一種語言寫的同一層的代碼(但都實現了程序指定的接口),我們在給類起名字的時候,只要用相同的類名就可以通過僅修改配置文件,達到換層的目的,而無需在工廠中改動任何代碼。比如說,我現在要把DAL層換成AccessDAL,那么僅需要做如下修改即可。
[html]?view plaincopy
<add?key="DAL"??value="AccessDAL"?/>??
這就是分層的好處,當然也是面向對象思想的優勢了。
上面主要是解釋了一下配置文件,來看看業務邏輯工廠代碼:
[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、數據訪問層工廠代碼類似:
[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、業務邏輯層接口代碼比較簡單,只需要定義一些相關接口方法即可,但是這里面體現了系統的架構,看似代碼簡單,實則反應程序員的架構水平。
[vb]?view plaincopy
Public?Interface?IUserBLL?? ?? ?????? ????Function?LogIn(ByVal?modelUser?As?Model.User)?As?String?? ?? End?Interface??
6、數據訪問層接口:
[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、業務邏輯層:
[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("用戶名錯誤!")?? ????????????????Return?Nothing?? ????????????????Exit?Function?? ????????????End?If?? ????????????If?dalFactory.CreateUserDAL.GetPwd(modelUser)?=?""?Then?? ????????????????MsgBox("密碼名錯誤!")?? ????????????????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、數據訪問層:
[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層了:注意這里還沒有添加針對用戶輸入合法性的驗證,如,用戶名、密碼輸入是否為空,是否符合指定格式等。
[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("未知錯誤!")?? ????????????????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??
到此為止,一個簡單的三層架構就算實現了,隱約感覺設計上有些地方不合理,但說不好存在于哪些地方,希望由此路過的大牛們,多多指教,另外,這里的數據訪問層代碼冗余較多,在后續的博客中,會通過編寫一個SQLHelp來實現優化,還有UML包圖也會在后續博客中天上。
最后說說我自己的感觸。
針對架構:用到了兩個抽象工廠,剛開始是將兩個工廠寫到了一層中,這層的名稱就叫Factory,而且封裝注入的類也一并放到了這層中,但是在調試程序的時候出現DAL層依賴循環調用錯誤,不知道是代碼還是設計上的原因?
針對接口設計:不太清楚業務邏輯層的方法設計是否合理,現在的一個問題就是如果用戶名或者密碼出錯的話,并不是由UI層向用戶提供反饋信息,而是由業務邏輯層擔當了此任務,暫且就這么寫吧,估計到后面寫的多了就找到合適的方法了。
總結
以上是生活随笔為你收集整理的抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。