工厂模式的应用实例


就拿机房收费系统来说吧。

NUMBER ONE

单纯的用抽象工厂来实现。这样的好处,是从整个系统的全局出发,而不单单从原始的D看待,古人云:父母之爱子则为之计深远。这使得系统更容易扩展了。因为这里面除了SQLHelper都使用了实体包,实体包的线就省略了。

NUMBER TWO

"简单工厂"去改造的抽象工厂。

这里说的简单工厂只是因为它没有工厂接口。而事实上因为我们的机房收费系统是用对一簇产品进行创建使用,按理说一簇产品应该是抽象工厂的。这样的好处是,在D层实现了解耦,和抽象工厂比起来,我们要扩展的话,BLL层和IFactory改动较大。

NUMBER THREE

"简单工厂"和抽象工厂结合改造后,再加上配置文件。

与NUMBER ONE不同的是去掉一条线。这样子的好处是去除了DALFactory与实际功能类DAL的耦合。

当然如果找个平衡点的话,我们的最佳选择是用NUMBER THREE

代码如下。(一下代码均以登录为例。UI省略)

NUMBER ONE

BLL层。

'------------------------------------------------------------------------------ '<copyrightfile="DALUser.vb"company="FANG"> 'Copyright(c)2012FANG.Allrightsreserved. '<copyright> '<author>TheSkyAlwaysSunshine<author> '<author>我的博客地址http://blog.csdn.net/xhf55555</author> '<date>2012年2月3日<date> '<description> 'BLL层之登录。 '<description> '------------------------------------------------------------------------------ PublicClassBLL_Login PublicFunctionLogin(ByValUserAsEntity.EN_User)AsBoolean DimmyUserAsNewEntity.EN_User '确定实例化哪个数据库给Factory,来实现换DB。 DimfactoryAsIfactory.Ifactory=NewDALFactory.SqlserverFactory DimIUserAsIDAL.IUser '与具体的数据库访问解除了依赖。 IUser=factory.CheckUser() myUser=IUser.GetUser(User) IfmyUser.UserPwd=User.UserPwdThen ReturnTrue Else ReturnFalse EndIf EndFunction EndClass


IDAL层。

'''<summary> '''用户表功能接口。 '''</summary> '''<remarks></remarks> PublicInterfaceIUser FunctionGetUser(ByValUserAsEntity.EN_User)AsEntity.EN_User EndInterface

DAL层。(以SqlserverUser为例。)

PublicClassSqlserverUser:ImplementsIDAL.IUser PublicFunctionGetUser(ByValUserAsEntity.EN_User)AsEntity.EN_UserImplementsIDAL.IUser.GetUser DimConnStrAsString="DataSource=192.168.24.169;InitialCatalog=PC_ChargeSys;UserID=sa;Pwd=123456" DimconnAsSqlConnection=NewSqlConnection(ConnStr) 'DimconnectionAsNewSQLHelp.ConnectionHelp DimsqlAsString="select*fromtb_UserwhereUserID='"&User.UserID&"'" DimcmdAsSqlCommand=NewSqlCommand(sql,conn) DimreadAsSqlDataReader DimmyUserAsNewEntity.EN_User Try conn.Open() read=cmd.ExecuteReader read.Read() myUser.UserID=read.Item("") myUser.UserPwd=read.Item("UserPwd") ReturnmyUser CatchexAsException myUser.UserID=0 myUser.UserPwd="" ReturnmyUser EndTry EndFunction EndClass


IFactory层。

'''<summary> '''定义操作工厂接口。 '''</summary> '''<remarks></remarks> PublicInterfaceIfactory FunctionCheckUser()AsIDAL.IUser EndInterface


SqlserverFactory具体操作工程类。

'------------------------------------------------------------------------------ '<copyrightfile="DALUser.vb"company="FANG"> 'Copyright(c)2012FANG.Allrightsreserved. '<copyright> '<author>TheSkyAlwaysSunshine<author> '<author>我的博客地址http://blog.csdn.net/xhf55555</author> '<date>2012年2月3日<date> '<description> '具体的操作类工厂实现抽象的功能类接口。 '<description> '------------------------------------------------------------------------------ PublicClassSqlserverFactory:ImplementsIfactory.Ifactory PublicFunctionCheckUser()AsIDAL.IUserImplementsIfactory.Ifactory.CheckUser ReturnNewDAL.SqlserverUser EndFunction EndClass


AccessFactory(与Sqlserver相似,不再赘余。)

User实体类。

'User实体类。 PublicClassEN_User DimintUserIDAsInteger'定义用户编号变量。 DimstrUserNameAsString'定义用户姓名变量。 DimstrUserPwdAsString'定义用户密码变量名。 DimstrUserActorAsString'定义用户角色变量。 DimvntUserRegDateAsDate'定义用户注册日期。 DimstrUserFlagAsString'定义用户是否合法的标记的变量。 DimstrUserTypeAsString'定义用户类型变量。 '''<summary> '''用户编号属性方法。 '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserID()AsInteger Get ReturnintUserID EndGet Set(ByValvalueAsInteger) intUserID=value EndSet EndProperty '''<summary> '''定义用户名属性方法。 '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserName()AsString Get ReturnstrUserName EndGet Set(ByValvalueAsString) strUserName=value EndSet EndProperty '''<summary> '''定义用户密码属性方法。 '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserPwd()AsString Get ReturnstrUserPwd EndGet Set(ByValvalueAsString) strUserPwd=value EndSet EndProperty '''<summary> '''定义用户角色属性方法。 '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserActor()AsString Get ReturnstrUserActor EndGet Set(ByValvalueAsString) strUserActor=value EndSet EndProperty '''<summary> '''定义注册日期变量。 '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserRegDateAsDate Get ReturnvntUserRegDate EndGet Set(ByValvalueAsDate) vntUserRegDate=value EndSet EndProperty '''<summary> '''定义用户是否合法的标记。(看是否是已经注销) '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserFlagAsString Get ReturnstrUserFlag EndGet Set(ByValvalueAsString) strUserFlag=value EndSet EndProperty '''<summary> '''定义用户类型变量(是固定用户还是临时用户) '''</summary> '''<value></value> '''<returns></returns> '''<remarks></remarks> PublicPropertyUserTyep()AsString Get ReturnstrUserType EndGet Set(ByValvalueAsString) strUserType=value EndSet EndProperty EndClass

我们再看NUMBER TWO 用简单工厂改造的抽象工厂。

我们是去掉了IFactory工厂接口和他手下的具体工厂操作类,而用一个DALFactory代替解决。这样把对功能类的判断放到了DALFactory里通过SelectCase来进行判断而不是通过实例化来判断了。

UI、IUser、AccessUser、SqlserverUser是不变的。所以在以上基础上改变 ,代码如下。

BLL层代码。

''' <summary> ''' 用户登录业务逻辑。 ''' </summary> ''' <remarks></remarks> Public Class BLL_Login Public Function Login(ByVal User As Entity.EN_User) As Boolean Dim myUser As New Entity.EN_User '通过具体的操作工厂实现要判断使用哪个数据库。 Dim Dalfactory As New DALFactory.DFactory Dim IUser As IDAL.IUser '与具体的数据库访问解除了依赖。 IUser = Dalfactory.CreateUserInfo() myUser = IUser.GetUser(User) If myUser.UserPwd = User.UserPwd Then Return True Else Return False End If End Function End Class


DALFactory层。

Imports IDAL ''' <summary> ''' 操作工厂类。 ''' </summary> ''' <remarks></remarks> Public Class DFactory 'Dim DataBase As String = "Access" Dim DataBase As String = "Sql" Function CreateUserInfo() As IDAL.IUser Dim db As IUser Select Case DataBase Case "Sql" db = New DAL.SqlserverUser 'Case "Access" ' db = New DAL.AccessUser End Select Return db End Function

NUMBER THREE我们是改变了操作工厂case而用反射的方法,和case说拜拜。我们用case判断太过于发死,把字符串写死在了DALFactory中,我们对功能类的使用,不是功能类本身去决定自己。我们要自己决定自己的人生大事,所以用反射就可以了。这样解除了分支判断的耦合。

DALFactory代码。

Imports IDAL Imports System.Reflection ''' <summary> ''' 操作工厂类。 ''' </summary> ''' <remarks></remarks> Public Class DFactory 'Dim DataBase As String = "Access" 'Dim DataBase As String = "Sql" Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("DBString") Function CreateUserInfo() As IDAL.IUser Return CType(Assembly.Load("DAL").CreateInstance("DAL.SqlserverUser" & strDB), IDAL.IUser) End Function End Class


具体的功能类SqlserverUser,只是改了一句话。

Public Class SqlserverUser : Implements IDAL.IUser Public Function GetUser(ByVal User As Entity.EN_User) As Entity.EN_User Implements IDAL.IUser.GetUser 'Dim ConnStr As String = "Data Source=192.168.24.169;Initial Catalog=PC_ChargeSys;User ID=sa;Pwd=123456" Dim ConnStr As String = System.Configuration.ConfigurationSettings.AppSettings("ConnStr") Dim conn As SqlConnection = New SqlConnection(ConnStr) 'Dim connection As New SQLHelp.ConnectionHelp 'connection.Connect() Dim sql As String = "select * from tb_User where UserID='" & User.UserID & "'" Dim cmd As SqlCommand = New SqlCommand(sql, conn) Dim read As SqlDataReader Dim myUser As New Entity.EN_User Try conn.Open() read = cmd.ExecuteReader read.Read() myUser.UserID = read.Item("") myUser.UserPwd = read.Item("UserPwd") Return myUser Catch ex As Exception myUser.UserID = 0 myUser.UserPwd = "" Return myUser End Try End Function End Class


工厂模式的基本原理见:http://blog.csdn.net/xhf55555/article/details/7609272

综上,我们把简单工厂、工厂方法、和抽象工厂三个模式在实际应用中进行了比较。我们的最佳组合是简单工厂改造的抽象工厂加上配置文件,耦合度和系统的开闭(对扩展开放、对修改封闭)、系统的可维护和灵活性尽在我们的三个包图中。笔者(me)认为,我们的设计模式就像数学公式,灵活运用就好。我们在开发一个系统的时候思考问题不要从上向下的思考方式,我们要从下向上,不是因为解耦而解耦,而是我们从系统长远的角度出发,使得我们在系统在不断的重构中发现问题,才去不断的思考,进一步的抽象,使得系统更加完美。没有完美的系统,只有完美的过程。

问题多多,欢迎您前来指教!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值