失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化

抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化

时间:2023-08-22 03:42:20

相关推荐

抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化

分层思想的一个核心就是部件化,各个层之间是相互独立的,每一层可以随便抽取换成一个其他语言的版本,但只要与相应的接口吻合就行。

我用的三层架构大致是这样的,基本的三层就不说了,然后分别为业务逻辑层和数据访问层定义一个接口,由具体的那个层来实现,问题产生了,由谁来指定程序使用哪个具体的对象来实现相应接口?

为解决这个问题,我应用的是抽象工厂模式。分别为业务逻辑层和数据访问层添加一个抽象工厂。具体架构还是看下图吧。

这里的Utility是一个工具类,在下文中会提到。

学过设计模式的人都应该听过反射技术,但是一个系统中用到的类很多,需要对每一个类进行实例化,如果仅利用抽象工厂+反射模式,重复的代码比较多,如果哪一天整个DAL层发生变更,那么就要在代码中修改每一个用到的地方,不仅不容易维护,而且还很容易出错,未解决这个问题,对程序作了一个优化——用到依赖注入。还是看看代码吧。

1、先看看依赖注入的容器:这里我把这个注入容器放到了工具类中,刚开始学习设计模式,不知道是否合理,欢迎高手们指点。

[vb]view plaincopyImportsSystem.Configuration ImportsSystem.Reflection PublicClassDependencyInjector '''<summary> '''利用反射机制,取得数据访问层对象 '''</summary> '''<paramname="className">传入数据访问层中要实例化的类的名称</param> '''<returns>指定的数据访问层的类</returns> '''<remarks></remarks> PublicFunctionGetDALObject(ByValclassNameAsString)AsObject DimdalAsObject DimdalNameAsString DimfullClassNameAsString DimdalObjAsObject '通过配置文件的指定要应用的DAL层 dal=System.Configuration.ConfigurationManager.AppSettings("DAL") 'dalName就是常说的用用程序的名称 dalName=dal.ToString '命名空间+类的名称,指明要实例化的类的路径 fullClassName=dalName+"."+className '通过反射,取得数据访问层对象 dalObj=Assembly.Load(dalName).CreateInstance(fullClassName) '返回指定的对象 ReturndalObj EndFunction '''<summary> '''取得指定业务逻辑层的指定类 '''</summary> '''<paramname="className">要应用的业务逻辑层的具体类的名称</param> '''<returns>指定的业务逻辑层的类(对象)</returns> '''<remarks></remarks> PublicFunctionGetBLLObject(ByValclassNameAsString)AsObject DimbllAsObject DimbllNameAsString DimbllObjAsObject DimfullClassNameAsString '从配置文件中读取业务逻辑名称 bll=System.Configuration.ConfigurationManager.AppSettings("BLL") bllName=bll.ToString fullClassName=bllName+"."+className '利用反射取得业务逻辑层对象 bllObj=Assembly.Load(bllName).CreateInstance(fullClassName) ReturnbllObj EndFunction EndClass

2、相关配置文件:

[html]view plaincopy<appSettings> <addkey="connStr"value="PersistSecurityInfo=true;DataSource=*****;InitialCatalog=Charge_Sys_SelfDesign;UserID=sa;PWD=****;"/> <addkey="DAL"value="DAL"/> <addkey="BLL"value="BLL"/> </appSettings>

3、业务逻辑层工厂:这里以在工厂中生产一个UserBLL类为例,在工厂中添加CreateUserBLL()方法,理论上讲,业务逻辑层有多少个类在此工厂中就要有多少个相应的方法,但是针对不同语言写的或者是不同的程序员用同一种语言写的同一层的代码(但都实现了程序指定的接口),我们在给类起名字的时候,只要用相同的类名就可以通过仅修改配置文件,达到换层的目的,而无需在工厂中改动任何代码。比如说,我现在要把DAL层换成AccessDAL,那么仅需要做如下修改即可。

[html]view plaincopy<addkey="DAL"value="AccessDAL"/>

这就是分层的好处,当然也是面向对象思想的优势了。

上面主要是解释了一下配置文件,来看看业务逻辑工厂代码:

[vb]view plaincopyImportsIBLL ImportsUtility ImportsSystem.Configuration ImportsSystem.Reflection ImportsSystem.Windows.Forms PublicClassCreateBLL PrivatedependecyAsNewUtility.DependencyInjector '''<summary> '''生成用户业务逻辑层访问对象 '''</summary> '''<returns></returns> '''<remarks></remarks> PublicFunctionCreateUserBLL()AsIBLL.IUserBLL Try '如果不用注入,需要重复N次BLL, 'ReturnCType(Assembly.Load("BLL").CreateInstance("BLL.UserBLL"),IBLL.IUserBLL) '优化后只需指明具体类名,如果要换层,只需到配置文件中做简单修改即可,程序代码清晰,不宜出错。 ReturnCType(dependecy.GetBLLObject("UserBLL"),IBLL.IUserBLL) CatchexAsException MsgBox(ex.Message) ReturnNothing EndTry EndFunction EndClass

4、数据访问层工厂代码类似:

[vb]view plaincopyImportsUtility ImportsSystem.Configuration ImportsSystem.Reflection ImportsIDAL ImportsSystem.Windows.Forms PublicClassCreateDAL PrivatedependencyAsNewUtility.DependencyInjector '''<summary> '''生成用户指定的数据访问层对象 '''</summary> '''<returns></returns> '''<remarks></remarks> PublicFunctionCreateUserDAL()AsIDAL.IUserDAL Try 'ReturnCType(Assembly.Load("DAL").CreateInstance("DAL.UserDAL"),IDAL.IUserDAL) ReturnCType(dependency.GetDALObject("UserDAL"),IDAL.IUserDAL) CatchexAsException MessageBox.Show(ex.Message) ReturnNothing EndTry EndFunction EndClass

5、业务逻辑层接口代码比较简单,只需要定义一些相关接口方法即可,但是这里面体现了系统的架构,看似代码简单,实则反应程序员的架构水平。

[vb]view plaincopyPublicInterfaceIUserBLL '返回用户登录的身份级别,在接口的实现中要验证用户名和密码 FunctionLogIn(ByValmodelUserAsModel.User)AsString EndInterface

6、数据访问层接口:

[vb]view plaincopyPublicInterfaceIUserDAL '获取用户ID FunctionGetID(ByValmodelUserAsModel.User)AsString '获取用户密码 FunctionGetPwd(ByValmodelUserAsModel.User)AsString '获取用户级别 FunctionGetLevel(ByValmodelUserAsModel.User)AsString EndInterface

7、业务逻辑层:

[vb]view plaincopyImportsDALFactory ImportsIBLL ImportsIDAL ImportsModel ImportsSystem.Data.SqlClient ImportsSystem.Collections.Generic PublicClassUserBLL ImplementsIBLL.IUserBLL PrivatedalFactoryAsNewDALFactory.CreateDAL '''<summary> '''先判断用户名和密码是否正确,然后返回用户级别 '''</summary> '''<paramname="modelUser">用户实体类</param> '''<returns>用户级别</returns> '''<remarks></remarks> PublicFunctionLogIn(ByValmodelUserAsModel.User)AsStringImplementsIBLL.IUserBLL.LogIn DimuserLevelAsString Try IfdalFactory.CreateUserDAL.GetID(modelUser)=""Then MsgBox("用户名错误!") ReturnNothing ExitFunction EndIf IfdalFactory.CreateUserDAL.GetPwd(modelUser)=""Then MsgBox("密码名错误!") ReturnNothing ExitFunction EndIf '通过数据访问层工厂指定实现数据访问层接口的具体的数据访问层以及该层的具体类 userLevel=dalFactory.CreateUserDAL.GetLevel(modelUser) CatchexAsException ReturnNothing EndTry ReturnuserLevel EndFunction EndClass

8、数据访问层:

[vb]view plaincopyImportsSystem.Data.SqlClient ImportsUtility ImportsSystem.Windows.Forms PublicClassUserDAL '实现数据访问层的接口 ImplementsIDAL.IUserDAL PrivatesqlHelpAsNewUtility.SQLServerDALHelp '''<summary> '''读取用户ID '''</summary> '''<paramname="modelUser">用户实体类</param> '''<returns>用户ID</returns> '''<remarks></remarks> PublicFunctionGetID(ByValmodelUserAsModel.User)AsStringImplementsIDAL.IUserDAL.GetID DimUser_IDAsString DimconnAsNewSqlConnection(sqlHelp.connStr) DimspNameAsString spName="proc_GetUserID" DimcmdAsNewSqlCommand(spName,conn) mandType=CommandType.StoredProcedure DimParamAsSqlParameter Param=NewSqlParameter("@User_ID",SqlDbType.VarChar) Param.Value=modelUser.User_ID cmd.Parameters.Add(Param) Try conn.Open() User_ID=cmd.ExecuteScalar.ToString ReturnUser_ID CatchexAsException MsgBox(ex.Message) ThrowNewException(ex.Message) Finally conn.Close() cmd.Dispose() cmd=Nothing EndTry ReturnUser_ID EndFunction '''<summary> '''读取用户密码 '''</summary> '''<paramname="modelUser">用户实体类</param> '''<returns>密码</returns> '''<remarks></remarks> PublicFunctionGetPwd(ByValmodelUserAsModel.User)AsStringImplementsIDAL.IUserDAL.GetPwd Dimuser_PwdAsString DimspNameAsString spName="proc_GetUserPwd" DimconnAsNewSqlConnection(sqlHelp.connStr) DimcmdAsNewSqlCommand(spName,conn) mandType=CommandType.StoredProcedure DimParamAsSqlParameter Param=NewSqlParameter("@User_Pwd",SqlDbType.VarChar) Param.Value=modelUser.User_Pwd cmd.Parameters.Add(Param) Param=NewSqlParameter("@User_ID",SqlDbType.VarChar) Param.Value=modelUser.User_Pwd cmd.Parameters.Add(Param) Try conn.Open() user_Pwd=cmd.ExecuteScalar.ToString CatchexAsException MsgBox(ex.Message) ThrowNewException(ex.Message) Finally conn.Close() cmd.Dispose() cmd=Nothing EndTry Returnuser_Pwd EndFunction '''<summary> '''读取用户身份级别 '''</summary> '''<paramname="modelUser">用户实体类</param> '''<returns>身份级别</returns> '''<remarks></remarks> PublicFunctionGetLevel(ByValmodelUserAsModel.User)AsStringImplementsIDAL.IUserDAL.GetLevel DimUser_LevelAsString DimspNameAsString spName="proc_GetUserLevel" DimconnAsNewSqlConnection(sqlHelp.connStr) DimcmdAsNewSqlCommand(spName,conn) mandType=CommandType.StoredProcedure DimParamAsSqlParameter Param=NewSqlParameter("@User_ID",SqlDbType.VarChar) Param.Value=modelUser.User_ID cmd.Parameters.Add(Param) Try conn.Open() User_Level=cmd.ExecuteScalar.ToString CatchexAsException MsgBox(ex.Message) ThrowNewException(ex.Message) Finally conn.Close() cmd.Dispose() cmd=Nothing EndTry ReturnUser_Level EndFunction EndClass

9、总算到UI层了:注意这里还没有添加针对用户输入合法性的验证,如,用户名、密码输入是否为空,是否符合指定格式等。

[vb]view plaincopyImportsModel ImportsIBLL ImportsSystem.Collections.Generic ImportsBLLFactory PublicClassfrmLogIn PrivatebllFactoryAsNewBLLFactory.CreateBLL PrivateSubbtnLogIn_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesbtnLogIn.Click DimmodelUserAsNewModel.User DimuserLevelAsString modelUser.User_ID=txtUserID.Text modelUser.User_Pwd=txtUserPwd.Text '通过业务逻辑工厂指定业务逻辑接口要使用的具体的业务逻辑层中的具体类 userLevel=bllFactory.CreateUserBLL.LogIn(modelUser) SelectCaseuserLevel Case"一般用户" Case"操作员" Case"管理员" frmMDIParentForm.Show() CaseElse MsgBox("未知错误!") ExitSub EndSelect EndSub PrivateSubbtnExit_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesbtnExit.Click txtUserID.Text="" txtUserPwd.Text="" Me.Close() EndSub EndClass

到此为止,一个简单的三层架构就算实现了,隐约感觉设计上有些地方不合理,但说不好存在于哪些地方,希望由此路过的大牛们,多多指教,另外,这里的数据访问层代码冗余较多,在后续的博客中,会通过编写一个SQLHelp来实现优化,还有UML包图也会在后续博客中天上。

最后说说我自己的感触。

针对架构:用到了两个抽象工厂,刚开始是将两个工厂写到了一层中,这层的名称就叫Factory,而且封装注入的类也一并放到了这层中,但是在调试程序的时候出现DAL层依赖循环调用错误,不知道是代码还是设计上的原因?

针对接口设计:不太清楚业务逻辑层的方法设计是否合理,现在的一个问题就是如果用户名或者密码出错的话,并不是由UI层向用户提供反馈信息,而是由业务逻辑层担当了此任务,暂且就这么写吧,估计到后面写的多了就找到合适的方法了。

如果觉得《抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。