现在的位置: 首页 > 综合 > 正文

工厂模式的应用实例

2013年09月10日 ⁄ 综合 ⁄ 共 8575字 ⁄ 字号 评论关闭

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

NUMBER ONE

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

NUMBER TWO

 

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

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

NUMBER THREE

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

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

 

 

 

 

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

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

NUMBER ONE

BLL层。

'------------------------------------------------------------------------------
' <copyright file="DALUser.vb" company="FANG">
' Copyright (c) 2012 FANG. All rights reserved.
' <copyright>
' <author>The Sky Always Sunshine<author>
' <author>我的博客地址http://blog.csdn.net/xhf55555</author>
' <date>2012年2月3日<date>
' <description>
'BLL层之登录。
' <description>
'------------------------------------------------------------------------------
Public Class BLL_Login
 
    Public Function Login(ByVal User As Entity.EN_User) As Boolean
        Dim myUser As New Entity.EN_User
        '确定实例化哪个数据库给Factory,来实现换DB。
        Dim factory As Ifactory.Ifactory = New DALFactory.SqlserverFactory
        Dim IUser As IDAL.IUser
        '与具体的数据库访问解除了依赖。
        IUser = factory.CheckUser()
        myUser = IUser.GetUser(User)
        If myUser.UserPwd = User.UserPwd Then
            Return True
        Else
            Return False
        End If
 
    End Function
 
End Class

IDAL层。

 

''' <summary>
''' 用户表功能接口。
''' </summary>
''' <remarks></remarks>
Public Interface IUser
    Function GetUser(ByVal User As Entity.EN_User) As Entity.EN_User
End Interface

DAL层。(以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 conn As SqlConnection = New SqlConnection(ConnStr)
 
        ' Dim connection As New SQLHelp.ConnectionHelp
        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

 

IFactory层。

''' <summary>
''' 定义操作工厂接口。
''' </summary>
''' <remarks></remarks>
Public Interface Ifactory
    Function CheckUser() As IDAL.IUser
End Interface

 SqlserverFactory具体操作工程类。

'------------------------------------------------------------------------------
' <copyright file="DALUser.vb" company="FANG">
' Copyright (c) 2012 FANG. All rights reserved.
' <copyright>
' <author>The Sky Always Sunshine<author>
' <author>我的博客地址http://blog.csdn.net/xhf55555</author>
' <date>2012年2月3日<date>
' <description>
'具体的操作类工厂实现抽象的功能类接口。
' <description>
'------------------------------------------------------------------------------
Public Class SqlserverFactory : Implements Ifactory.Ifactory
    Public Function CheckUser() As IDAL.IUser Implements Ifactory.Ifactory.CheckUser
        Return New DAL.SqlserverUser
    End Function
End Class

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

 

User实体类。

'User实体类。
Public Class EN_User
    Dim intUserID As Integer  '定义用户编号变量。
    Dim strUserName As String  '定义用户姓名变量。
    Dim strUserPwd As String '定义用户密码变量名。
    Dim strUserActor As String '定义用户角色变量。
    Dim vntUserRegDate As Date '定义用户注册日期。
    Dim strUserFlag As String '定义用户是否合法的标记的变量。
    Dim strUserType As String '定义用户类型变量。
    ''' <summary>
    ''' 用户编号属性方法。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserID() As Integer
        Get
            Return intUserID
        End Get
 
        Set(ByVal value As Integer)
            intUserID = value
        End Set
    End Property
    ''' <summary>
    ''' 定义用户名属性方法。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserName() As String
        Get
            Return strUserName
        End Get
        Set(ByVal value As String)
            strUserName = value
        End Set
    End Property
    ''' <summary>
    ''' 定义用户密码属性方法 。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserPwd() As String
        Get
            Return strUserPwd
        End Get
        Set(ByVal value As String)
            strUserPwd = value
        End Set
    End Property
    ''' <summary>
    ''' 定义用户角色属性方法。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserActor() As String
        Get
            Return strUserActor
        End Get
        Set(ByVal value As String)
            strUserActor = value
        End Set
    End Property
    ''' <summary>
    ''' 定义注册日期变量。
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserRegDate As Date
        Get
            Return vntUserRegDate
        End Get
        Set(ByVal value As Date)
            vntUserRegDate = value
        End Set
    End Property
    ''' <summary>
    ''' 定义用户是否合法的标记。(看是否是已经注销)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserFlag As String
        Get
            Return strUserFlag
        End Get
        Set(ByVal value As String)
            strUserFlag = value
        End Set
    End Property
    ''' <summary>
    ''' 定义用户类型变量(是固定用户还是临时用户)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property UserTyep() As String
        Get
            Return strUserType
        End Get
        Set(ByVal value As String)
            strUserType = value
        End Set
    End Property
 
End Class

我们再看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)认为,我们的设计模式就像数学公式,灵活运用就好。我们在开发一个系统的时候思考问题不要从上向下的思考方式,我们要从下向上,不是因为解耦而解耦,而是我们从系统长远的角度出发,使得我们在系统在不断的重构中发现问题,才去不断的思考,进一步的抽象,使得系统更加完美。没有完美的系统,只有完美的过程。

 

 

 

 

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

 

抱歉!评论已关闭.