个人版机房收费系统——抽象工厂+反射+配置文件实现系统登录

因为之前用的纯三层的思想,所有的业务逻辑均在三层之间来回传递,包括U层的获得控件属性、传递参数到B层和接收从B层返回的数据,B层对业务逻辑的处理和D层操作数据库,在代码实现的过程中越来越觉得复杂和繁琐,最明显的地方就是数据库方面对数据的查询操作和非查询操作都有好多重复的地方,所有东西归纳总结一下无非就是查询和非查询,带参和不带参的查询,返回实体和返回datatable的区别,运用设计模式,封装这些有限的变化就非用到SqlHelper类了。然而对于方便系统要更换数据库和增加更多的功能所面临的问题,抽象工厂就是比较好的解决方案,我们用反射,仅仅修改一个字符串就能实现百分百的更换数据库,一个反射结合配置文件又最大限度的避免了抽象工厂运用过程中的不方便。
下面就是一个登录的简单实例,代码和详细的解释一定能让你看就懂!
包图:

(其实外观在系统登录的时候没有什么大的作用,我在设计整个机房架构的过程中选择了使用外观是为了方便以后的实现过程。)


分层设计:

总的思想仍然是三层,在这基础上增加的另外抽象工厂、外观、SqlHelper和IDAL数据库接口层。也只是把在纯三层中的代码分类整理分布到各个层中,增加接口层的主要作用大家也都清楚,我就不详细介绍了。每个层仍然只是干自己的事,尽量的符合每个类的单一职责原则。


界面设计:

很简单的系统登录界面。
 
UI层:U层负责数据的输入与输出,首先对输入的数据要求进行判定,符合要求之后调用外观的验证用户和密码的方法。调用方法和纯三层的基本一样。
'添加引用
Imports BLL
Imports Entity
Public Class FrmLogin
    Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
        '定义一个实体获得属性
        Dim enUser As New Entity.UserEntity
        enUser.struserID = txtUserID.Text.Trim()
        enUser.strpwd = txtPWD.Text.Trim()


        '判断是否输入了用户名及密码  
        If txtUserID.Text.Trim() = "" Then
            MessageBox.Show("请输入用户ID", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            txtUserID.Select()
            txtUserID.Focus()
            Exit Sub
        ElseIf IsNumeric(txtUserID.Text) = False Then
            MsgBox("用户ID请输入数字!")
            txtUserID.Text = ""
            txtUserID.Select()
            txtUserID.Focus()
            Exit Sub
        ElseIf txtPWD.Text.Trim() = "" Then
            MessageBox.Show("请输入用密码", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            txtPWD.Select()
            txtPWD.Focus()
            Exit Sub
        End If
        Try
            '定义一个外观层的对象
            Dim FacadeLogin As New Facade.LoginFacade


            Dim strResult1 As Boolean
            strResult1 = FacadeLogin.CheckUser(enUser)
            If strResult1 = False Then
                MsgBox("用户不存在")
                txtUserID.Text = ""
                txtUserID.Select()
                txtUserID.Focus()            
            End If


            Dim table As DataTable
            table = FacadeLogin.CheckPwd(enUser)
            If Trim(txtPWD.Text) = Trim(table.Rows(0).Item(2)) Then
                MsgBox("登录成功")
            Else
                MsgBox("密码不正确")
                txtPWD.Text = ""
                txtPWD.Select()
                txtPWD.Focus()
            End If
        Catch ex As Exception
            MsgBox("密码不正确")
            txtPWD.Text = ""
            txtPWD.Select()
            txtPWD.Focus()
        End Try

    End Sub


    Private Sub FrmLogin_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        txtUserID.Select()
        txtUserID.Focus()
    End Sub
End Class
外观层设计:外观层的两个方法真正实现的功能也类似于只是传参数而已,对于登录,外观层的作用不大,同样调用B层的方法
Public Class LoginFacade
    Public Function CheckUser(ByVal enUser As Entity.UserEntity) As Boolean
        '用于检查用户是否存在
        Dim IsUserExistsBLL As New BLL.IsExists
        Dim flag As Boolean
        flag = IsUserExistsBLL.IsUserExists(enUser)
        If flag = True Then
            Return True
        Else
            Return False
        End If
    End Function
    '检查密码是否正确
    Public Function CheckPwd(ByVal enUser As Entity.UserEntity) As DataTable
        Dim IsPwdBLL As New BLL.IsExists
        Dim table As DataTable
        table = IsPwdBLL.CheckUserPWD(enUser)
        Return table
    End Function

End Class


BLL层设计:验证用户是否存在和密码是否正确,验证方法通过工厂和IDAL接口进行,首先实例化工厂,然后定义接口变量,调用工厂中的方法,然后对返回数据进行的逻辑判断
Imports IDAL
Imports Entity
Public Class IsExists
    '检查用户是否存在
    Public Function IsUserExists(ByVal enUser As Entity.UserEntity) As Boolean
        '定义并实例化一个工厂,
        Dim factory As New Factory.DataAccess
        '定义一个接口变量
        Dim IUser As IUser
        '通过调用创建用户的工厂方法
        IUser = factory.CreateUser
        Dim table As DataTable
        Dim flag As Boolean
        table = IUser.CheckExistsUser(enUser)
        If table.Rows.Count = 0 Then
            flag = False
        Else
            flag = True
        End If
        Return flag
    End Function


    '检查密码是否正确
    Public Function CheckUserPWD(ByVal enUser As UserEntity) As DataTable
        Dim factory As New Factory.DataAccess '定义工厂并实例化工厂变量factory
        Dim IUser As IUser '定义接口变量IUser
        Dim table As DataTable '中间变量,用于存储D层查询到的数据
        IUser = factory.CreateUser '调用工厂的CreateUser方法创建iuser接口实例
        table = IUser.CheckExistsUser(enUser) '调用接口的方法UserIsExist,并将返回值返回给flag


        Return table
    End Function
End Class
工厂层设计:最经典的抽象工厂层的设计,用反射+配置文件,配置文件的讲解在上篇博客中详细介绍了,登录中应用的配置文件如下:
 

反射技术的核心就是对于如何应用字符串修改引起的变化,在反射的格式中涉及到的什么是程序集的名称,什么是命名空间,什么是类名,大家要清楚,不要搞混了,代码中对于这几个的写法要注意。


Imports System.Reflection
Imports System.Configuration
Imports IDAL
Public Class DataAccess
    Private Shared ReadOnly AssemblyName As String = "DAL" '定义程序集名称变量,D层的命名空间的名字
    Private Shared ReadOnly db As String = ConfigurationManager.AppSettings("DB") '将数据库类型通过文件形式读取到变量db中


    '创建用户的工厂
    Public Function CreateUser() As IUser
        Dim className As String = AssemblyName + "." + db + "User"
        Dim iuser As IUser


        iuser = CType(Assembly.Load(AssemblyName).CreateInstance(className), IUser)

        Return iuser
    End Function
End Class
IDAL层设计:定义一个接口用于对B层和D层之间解耦。
Public Interface IUser
    '检查用户是否存在和密码是否正确
    Function CheckExistsUser(ByVal enUser As Entity.UserEntity) As DataTable


End Interface

DAL层设计:连接数据库,如果查询带有参数,应该注意参数的添加形式,这里很容易出错,查询语句的写法,在数据库的学习中都应用到了,各种查询我的博客中也介绍过,这里就不详细说了。
Imports Entity
Imports IDAL
Imports System.Data.SqlClient
Public Class SqlserverUser : Implements IUser
    '查询用户和密码是否存在和正确
    Public Function SelectExistsUser(ByVal enUser As Entity.UserEntity) As DataTable Implements IUser.CheckExistsUser
        Dim sql As String '定义字符串变量sql,用于存放要执行的sql语句
        Dim table As DataTable '定义表变量table,用于存储执行的结果并返回
        Dim paras As SqlParameter() = {New SqlParameter("@userID", enUser.struserID),
                                       New SqlParameter("@pwd", enUser.strpwd)} '定义参数变量paras,用于命令执行时传递参数


        sql = "select * from T_UserInfo where userID=@userID and pwd=@pwd" '存储sql语句
        table = SqlHelper.SqlHelper.GetDataTable(sql, CommandType.Text, paras) '执行sql语句,将结果赋给table


        Return table
        'SelectExistsUser = table '返回表table
    End Function

End Class


SqlHelper层设计:这层的设计上篇博客中也详细讲解了!在登录中用到的是带参数的查询操作,返回的是datatable类型。注意的是在这层连接数据库的时候同样用到的是反射的思想。
'添加的引用
Imports System.Data.SqlClient
Imports System.Configuration


Public Class SqlHelper

    Private Shared ConnectionString As String = ConfigurationManager.AppSettings("strConn")
    ''' <summary>
    ''' 执行带参数的查询操作
    ''' </summary>
    ''' <param name="cmdTxt">参数cmdTxt为所要执行的sql语句</param>
    ''' <param name="cmdType">查询时的查询方式</param>
    ''' <param name="paras">查询时的命令参数paras</param>
    ''' <returns>查询后以表的方式返回,如下面的adataset.Tables(0)</returns>
    ''' <remarks></remarks>
    Public Shared Function GetDataTable(ByVal cmdTxt As String, ByVal cmdType As CommandType, ByVal paras As SqlParameter()) As DataTable


        Dim conn As SqlConnection = New SqlConnection(ConnectionString) '建立数据库连接
        Dim cmd As SqlCommand '定义命令变量cmd
        Dim adaptor As SqlDataAdapter '定义数据适配器
        Dim adataset As DataSet '定义并实例化数据缓冲区对象


        cmd = New SqlCommand(cmdTxt, conn) '在conn上面执行实例化命令变量,并执行语句cmdType
        cmd.CommandType = cmdType '命令执行的类型
        cmd.Parameters.AddRange(paras) '命令执行时的参数


        adaptor = New SqlDataAdapter(cmd) '将结果绑定到数据适配器变量adaptor上面
        adataset = New DataSet


        Try
            '如果数据库连接状态为关闭则将其打开
            If conn.State = ConnectionState.Closed Then
                conn.Open()
            End If
            adaptor.Fill(adataset) '向adaptor对象中填充查询的数据
        Catch ex As Exception
            '错误处理程序,出错则提示
            MsgBox(ex.Message, , "数据库操作")
        Finally
            '如果连接状态为打开则将其关闭,释放内存
            If conn.State = ConnectionState.Open Then
                conn.Close()
            End If
        End Try


        '以表格形式返回结果
        Return adataset.Tables(0)


    End Function
End Class


实体层设计:上面的每一层都要应用到实体层,可以说不管是三层还是多层,数据的传递都是依赖实体层进行的,这一层必不可少。实体层的设计离不开数据库表的设计,基本上每一个实体都是一张表的化身。可以看出表中的字段就是实体的属性,提醒一下,像获得自己的计算机名称这种变量可以定义为全局变量,我们可以把这种全局变量放到类模块中,这样整个系统都可以使用全局变量了。
Public Class UserEntity
    Private userID As String
    Private userName As String
    Private level As String
    Private pwd As String
    Public Property struserID() As String
        Get
            Return userID
        End Get
        Set(value As String)
            userID = value
        End Set
    End Property
    Public Property struserName() As String
        Get
            Return userName
        End Get
        Set(value As String)
            userName = value
        End Set
    End Property
    Public Property strlevel() As String
        Get
            Return level
        End Get
        Set(value As String)
            level = value
        End Set
    End Property
    Public Property strpwd() As String
        Get
            Return pwd
        End Get
        Set(value As String)
            pwd = value
        End Set
    End Property

End Class


整个登录的实例就到这里了,至于登录之后要添加用户值班情况这部分的代码自己去实现吧,采用分层的方式思路清晰,加上设计模式,使代码的复用性提高了,每一层和每一层的联系减少了,很好的达到了解耦和的目的。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值