机房收费系统之抽象工厂篇

机房收费系统之抽象工厂篇

        机房收费系统vb.net个人版已完成,在此过程中分层的好处在系统的完成过程中得到了很好的体会。第一遍用的是纯三层做的,这几天又在此基础上又重构了登录的demo,加上抽象工厂和配置文件的使用。下面以登录功能为例,总结一下我的机房收费系统。

一、下面看一下我的包图:

 

      可以看到,这张图是从最基本的三层UI→BLL→DAL加入设计模式(抽象工厂)演化而来的,采用抽象工厂是考虑到日后更换数据库的方便。

 

二、准备工作

       创建数据表(课参见实体类中的代码)

       创建相应的类库和窗体。

       我用的是vb.net的WidowsApplication来添加界面;使用类库作为其它层的包。

 

三、抽象各层的类

        当我们确定了系统的整体架构,就要从宏观到微观的实现。

3.1 Entity(实体层)

        数据库设计好了,我们要根据数据库中的表抽象实体类,系统中,实体类和表基本上是一一对象的。一个表映射一个实体类,表的字段即为实体类的属性。

        实体层并不属于三层的任何一层,它是独立出来的一层,可以把它看做是自定义变量的组合,供其它三层使用。

Public Class UserInfoEntity

#Region "定义UserInfo表中各个属性变量"
    Private _userName As String
    Private _name As String
    Private _password As String
    Private _userlevel As String
    Private _accountHolder As String
    Private _regDate As String
    Private _regTime As String
#End Region

#Region "定义数据表中各个字段名常量"
    Private Const DBFLELD_USERNAME = "userName"
    Private Const DBFLELD_NAME = "name"
    Private Const DBFLELD_PASSWORD = "password"
    Private Const DBFLELD_USERLEVEL = "userLevel"
    Private Const DBFLELD_ACCOUNTHOLDER = "accountHolder"
    Private Const DBFLELD_REGDATE = "regDate"
    Private Const DBFLELD_TIME = "regTime"
#End Region

#Region "定义数据表中各个字段参数变量"
    Public Const DBPARAM_USERNAME = "@userName"
    Public Const DBPARAM_NAME = "@name"
    Public Const DBPARAM_PASSWORD = "@password"
    Public Const DBPARAM_USERLEVEL = "@userLevel"
    Public Const DBPARAM_ACCOUNTHOLDER = "@accountHolder"
    Public Const DBPARAM_REGDATE = "@regDate"
    Public Const DBPARAM_TIME = "@regTime"
#End Region

    ''' <summary>
    ''' 获取数据表中的一条记录
    ''' </summary>
    ''' <param name="dr">字段名</param>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Sub LoadFromDataRow(ByVal dr As DataRow)
        userName = dr(DBFLELD_USERNAME)
        name = dr(DBFLELD_NAME)
        password = dr(DBFLELD_PASSWORD)
        userlevel = dr(DBFLELD_USERLEVEL)
        accountHolder = dr(DBFLELD_ACCOUNTHOLDER)
        regDate = dr(DBFLELD_REGDATE)
        regTime = dr(DBFLELD_TIME)
    End Sub

#Region "填充一条记录"
    ''' <summary>
    ''' 填充一条记录(登录)到实体层
    ''' </summary>
    ''' <param name="AuserName">用户名</param>
    ''' <param name="Apassword">密码</param>
    ''' <param name="AuserLevel">用户级别</param>
    ''' <remarks>2013-5-9 by liu hai yan </remarks>
    Public Overloads Sub Fill(ByVal AuserName As String, ByVal Apassword As String, ByVal AuserLevel As String)
        userName = AuserName
        password = Apassword
        userlevel = AuserLevel
    End Sub
#End Region

#Region "定义数据表中各个属性"
    ''' <summary>
    ''' 用户名
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property userName() As String
        Get
            Return _userName
        End Get
        Set(ByVal value As String)
            _userName = value
        End Set
    End Property

    ''' <summary>
    ''' 用户姓名
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

    ''' <summary>
    ''' 用户密码
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property password() As String
        Get
            Return _password
        End Get
        Set(ByVal value As String)
            _password = value
        End Set
    End Property

    ''' <summary>
    ''' 用户权限
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property userlevel() As String
        Get
            Return _userlevel
        End Get
        Set(ByVal value As String)
            _userlevel = value
        End Set
    End Property

    ''' <summary>
    ''' 开户人
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property accountHolder() As String
        Get
            Return _accountHolder
        End Get
        Set(ByVal value As String)
            _accountHolder = value
        End Set
    End Property

    ''' <summary>
    ''' 注册日期
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property regDate() As String
        Get
            Return _regDate
        End Get
        Set(ByVal value As String)
            _regDate = value
        End Set
    End Property

    ''' <summary>
    ''' 注册时间
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property regTime() As String
        Get
            Return _regTime
        End Get
        Set(ByVal value As String)
            _regTime = value
        End Set
    End Property
#End Region

End Class

 

       下面是配置文件的使用:在窗体层添加新项目→选中打开窗口的左边的General选项→添加配置文件,(中间部分是需要手动添加的)。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

	<appSettings >
		<add key="connStr" value ="Data Source=.;Initial Catalog=Login;User ID=sa;Password=123456"/>
		<add key ="AssemblyName" value ="DAL"/>
		<add key ="db" value ="DB"/>
	</appSettings>

    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
    </startup>
</configuration>

 

3.2 DAL层(数据访问层)

    接下来我们再看一下数据访问层(DAL),这一层的主要任务是直接操作数据库,完成对数据的增删改查等。这里我们仍然根据数据表来抽象DAL层的类,基本上也是一个表对应一个类,这样当我们增加新的表,直接增加新的DAL层类就可以,很好地符合了“开闭原则”。

另外,因为DAL层的类是直接对数据库进行操作的类,所以这个类里封转大都有四种方法:增删改查。但根据实际情况会有不同的参数,不同的返回值。

       这里添加了接口层IDAL,利用反射和抽象工厂,以防更换数据库。

3.2.1 接口层IDAL,添加Entity的引用。

Imports Entity

Public Interface Iuser
    ''' <summary>
    ''' 查看一条记录是否存在
    ''' </summary>
    ''' <param name="entityUser">用户信息</param>
    ''' <returns>一条用户记录</returns>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Function Check(ByVal entityUser As UserInfoEntity) As UserInfoEntity
End Interface

 

3.2.2 DAL层实现IDAL接口

        下面是DAL层下的DataAccess类

        添加Configuration引用时需从.net子项目中查找,还要添加项目引用Entity和IDAL.

'如果没有使用配置文件加反射,不用引用Configuration和Reflection
Imports System.Configuration
Imports System.Reflection
Imports System.Data.SqlClient
Imports Entity
Imports IDAL

Public Class DataAccess

#Region "连接数据库"
    Private ReadOnly connStr As String = ConfigurationManager.AppSettings("connStr")
    ''' <summary>
    ''' 创建一个数据库连接
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Overloads Function CreateConn() As SqlConnection
        Return New SqlConnection(connStr)
    End Function
#End Region

#Region "关闭相关对象"
    ''' <summary>
    ''' 关闭SqlConnection对象
    ''' </summary>
    ''' <param name="conn">连接数据库</param>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Sub Close(ByVal conn As SqlConnection)
        conn.Close()
        conn = Nothing
    End Sub

    ''' <summary>
    ''' 关闭SqlCommand对象
    ''' </summary>
    ''' <param name="cmd">sql命令</param>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Sub Close(ByVal cmd As SqlCommand)
        cmd.Dispose()
        cmd = Nothing
    End Sub
#End Region

    ''' <summary>
    ''' 为sql变量赋值并添加到SqlCommand中
    ''' </summary>
    ''' <param name="cmd">SqlCommand命令</param>
    ''' <param name="dbParam">参数名</param>
    ''' <param name="dbType">参数类型</param>
    ''' <param name="value">参数值</param>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Sub AddSqlParameter(ByVal cmd As SqlCommand, ByVal dbParam As String, ByVal dbType As SqlDbType, ByVal value As Object)
        Dim sqlParam As SqlParameter = New SqlParameter(dbParam, dbType)
        sqlParam.Value = value
        cmd.Parameters.Add(sqlParam)
    End Sub

End Class

 

        DAL层下的DBuser类

        同样添加项目引用Entity和IDAL.

Imports System.Data.SqlClient
Imports Entity
Imports IDAL

Public Class DBuser
    '前面BLL没有用抽象工厂的这里不用继承DataAccess
    Inherits DataAccess
    Implements Iuser

    Public Function Check(ByVal entityUser As Entity.UserInfoEntity) As UserInfoEntity Implements IDAL.Iuser.Check
        '这里的sql语句是为了以后的灵活性,将各个字段使用了常量来进行表示,具体可参见实体层
        Dim sql As String = String.Format("select * from userInfo where [userName]={0} and [password]={1} and [userLevel]={2}", UserInfoEntity.DBPARAM_USERNAME, UserInfoEntity.DBPARAM_PASSWORD, UserInfoEntity.DBPARAM_USERLEVEL)
        Dim conn As SqlConnection = CreateConn()
        Dim cmd As SqlCommand = New SqlCommand(sql, conn)
        Dim sda As SqlDataAdapter = New SqlDataAdapter(cmd)
        Dim ds As New DataSet

        '向cmd中添加参数
        AddSqlParameter(cmd, UserInfoEntity.DBPARAM_USERNAME, SqlDbType.VarChar, entityUser.userName)
        AddSqlParameter(cmd, UserInfoEntity.DBPARAM_PASSWORD, SqlDbType.VarChar, entityUser.password)
        AddSqlParameter(cmd, UserInfoEntity.DBPARAM_USERLEVEL, SqlDbType.VarChar, entityUser.userlevel)

        Try
            conn.Open()
            sda.Fill(ds, "userInfo")
            Dim dr As DataRow = ds.Tables("userInfo").Rows(0)
            entityUser.LoadFromDataRow(dr)
            Return entityUser
        Catch ex As Exception
            Return Nothing
        Finally
            Close(cmd)
            Close(conn)
        End Try
    End Function
End Class

 

      抽象工厂+反射+配置文件

Imports System.Configuration
Imports System.Reflection
Imports IDAL

Public Class Factory

#Region "配置加反射"
    Private Shared ReadOnly AssemblyName As String = ConfigurationManager.AppSettings("AssemblyName")
    Private Shared ReadOnly db As String = ConfigurationManager.AppSettings("db")
    ''' <summary>
    ''' 实例化Iuser类型的DBuser类对象
    ''' </summary>
    ''' <returns>DBuser类对象</returns>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Shared Function CreateUser() As Iuser
        Dim ClassName As String
        ClassName = AssemblyName + "." + db + "user"
        Return CType(Assembly.Load(AssemblyName).CreateInstance(ClassName), Iuser)
    End Function
#End Region

End Class



3.BLL层(封装业务层):前提添加DAL,IDAL和Entity的引用

Imports IDAL
Imports Entity
Imports Factory

Public Class BllLogin
    ''' <summary>
    ''' 查看登录信息是否存在
    ''' </summary>
    ''' <param name="entityUserInfo">窗体输入的用户信息</param>
    ''' <returns>登录是否成功</returns>
    ''' <remarks>2013-5-9 by liuhaiyan</remarks>
    Public Function CheckRecord(ByVal entityUserInfo As UserInfoEntity) As Boolean
        Dim checkResult As Boolean
        '下面声明的iuser是实例化的Iuser类型的DBuser,实现了接口的调用(接口虽然不能被实例化,但是继承它的类可实例化成接口类型)
        Dim iuser As Iuser
        '此处运用的是抽象工厂设计模式中的反射加配置,如果没有用设计模式可以讲下面的这句话改为:iuser=new DBuser()
        iuser = Factory.Factory.CreateUser()

        If Not IsNothing(iuser.Check(entityUserInfo)) Then
            checkResult = True
        Else
            checkResult = False
        End If

        Return checkResult
    End Function
End Class

4.UI层(界面层)

         界面层的类,就是我们窗体类,又多少个 窗体,UI层就有多少个类。

        下面我们看一下登录窗体类。

Imports BLL
Imports Entity

Public Class frmLogin
    '登录
    Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click
        '判断文本框是否为空
        If txtUserID.Text = "" Then
            MessageBox.Show("用户名不能为空!")
            txtUserID.Focus()
            Return
        End If

        If txtPassword.Text = "" Then
            MessageBox.Show("用户名不能为空!")
            txtPassword.Focus()
            Return
        End If

        '填充参数记录(此处调用的是实体层中实体类userInfo中的填充记录Fill方法,后面会有介绍)
        Dim entityUserInfo As New UserInfoEntity
        entityUserInfo.Fill(Trim(txtUserID.Text), Trim(txtPassword.Text), Trim(cboUserLevel.Text))

        '验证用户记录(调用BLL层中的验证用户记录CheckRecord方法)
        Dim bllUserInfo As New BllLogin
        If bllUserInfo.CheckRecord(entityUserInfo) Then
            Me.Hide()
            frmMain.Show()

            '判断用户级别
            ' ……
            '添加用户记录
            ' ……
        Else
            MsgBox("登录失败", vbOKOnly + vbInformation, "登录失败")
            txtUserID.Focus()
            Exit Sub
        End If
    End Sub

    '取消
    Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
        Me.Close()
    End Sub

End Class

     

        上面就是我在三层(UI→BLL→DAL)的基础上加上设计模式抽象工程实现系统登录的Demo,拿出来和大家一起分享,其中的不足之处,还希望大家多多指正。


 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值