机房重构:三层到七层

           经过了5天的努力,终于完成了三层到七层登录的华丽转身,开始很不知所措,三层实现之后一直忙着评教的维护工作,而且设计模式也好长时间没看了,直接实现七层不知道如何下手,就找了很多资料,看了很多大牛的博客,稀里糊涂照猫画虎,就敲完了,兴奋了一秒钟,试了试,根本传不到D层,就直接在U层抛错了,作为一名立志成为IT女超人的我是有这个心里准备的,怎么可能一次就成功呢,旅途一定是漫长且坎坷的,经过这两三天的调错经历,我感觉我对于调错的心态改变了很多:1.不能着急,越着急越理不清楚,简单的错也看不出来  2.要坚信,你一定能解决这个问题 。不说废话了,直接总结啦


七层构成

机房重构:三层到七层_第1张图片


传统的七层是有七个“包”的,但是上边多了一个SQLHelper的包,许多童鞋把这个类放到了DAL层,也有的像我一样重新分出一层,这都是没有关系的,只要引用关系对了,这都是无关紧要的。和三层对比可以发现,UI和BLL层多了一个外观层,BLL和DAL层中间多了一个接口层,还多了一个工厂层。


设想原来的程序,UI层调用BLL层的方法,而BLL层调用DAL层的方法,如果被调用层代码被更改,那么势必影响到调用层的代码,这就违背了开闭原则,好的系统提倡对更改关闭,对拓展开放,所以三层中各更次之间的耦合性还是非常强的。七层就是降低了原来三层的耦合程度。外观层解耦UI层和BLL层,而工厂的引入是为了利用反射原理,通过添加配置文件,读取配置文件,方便更换数据库,接口类是使得BLL层和DAL层解耦


外观模式

定义:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

结合机房:外观这一层会去自动要要传递信息的类,而不是UI层直接去找,UI层直接接受一个外观层返回的结果就好,他甚至不需要知道BLL层中有哪些内容,他只认识外观一个小伙伴就够了。看下边这个示意图,更清楚明了一些

机房重构:三层到七层_第2张图片


抽象工厂+反射


这里新添的工厂类和接口类使我们的系统在遇到变更数据库的时候,变得异常的便捷。如果不使用反射,那么就需要实例化DAL层的对象,而反射也可以指明需要实例的DAL层的对象。大家注意看下边类图中工厂类的属性中,DB是字符串,工厂类通过变量来实例化DAL层的对象,这样将程序由编译转化为运行时,而变量又是随时可以更换的,如果要更换数据库,在配置文件中更改相应的代码就能达到目的。


机房重构:三层到七层_第3张图片


时序图

这里只写了在数据库中查找是否存在这个用户的时序图,判读密码是否正确的图和这个大同小异,就不列举了

机房重构:三层到七层_第4张图片


代码

【实体层】

'**************************  
'文 件 名:LoginEntity  
'命名空间:Entity  
'内    容:  
'功    能:  
'文件关系:  
'作    者:陈丹  
'小    组:陈丹  
'生成日期:2015.12.21 15:30
'版 本 号:V1.0.0.0  
'修改日志:  
'版权说明:  
'*************************** 

Public Class LoginEntity

#Region "定义变量"
    Private _userid As String  '这个字段是为了方便在类内传值,所以是私有的
    Private _password As String
    Private _oldpassword As String
    Private _userlevel As String
    Private _head As String
    Private _userstatus As String
#End Region

    '定义全局变量
    Public Shared UserHead As String
    Public Property UserID As String
        Get
            Return _userid
        End Get
        Set(value As String)
            _userid = value
        End Set
    End Property

    Public Property PassWord As String
        Get
            Return _password
        End Get
        Set(value As String)
            _password = value
        End Set
    End Property

    Public Property OldPassword As String
        Get
            Return _oldpassword
        End Get
        Set(value As String)
            _oldpassword = value
        End Set
    End Property

    Public Property UserLevel As String
        Get
            Return _userlevel
        End Get
        Set(value As String)
            _userlevel = value
        End Set
    End Property

    Public Property Head As String
        Get
            Return _head
        End Get
        Set(value As String)
            _head = value
        End Set
    End Property

    Public Property UserStatus As String
        Get
            Return _head
        End Get
        Set(value As String)
            _head = value
        End Set
    End Property


End Class


【SQLHelper】

'**************************  
'文 件 名:sqlHelper  
'命名空间:SQLHelper  
'内    容:  
'功    能:  
'文件关系:  
'作    者:陈丹  
'小    组:陈丹  
'生成日期:2015.12.21 19:18
'版 本 号:V1.0.0.0  
'修改日志:  
'版权说明:  
'***************************  
Imports System.Data.SqlClient
Imports System.Configuration
Imports System.Data

Public Class sqlHelper

    '配置文件
    'Private ReadOnly strconnection As String = ConfigurationManager.AppSettings("strConnection")
    Dim strConnection As String = "server=.;Database=JFroom;User ID=sa;PassWord=1;"

    Dim conn As SqlConnection = New SqlConnection(strConnection)
    Dim cmd As New SqlCommand 
#Region "查询,返回结果集"
    ''' <summary>
    ''' 执行查询操作,返回DATATABLE
    ''' </summary>
    ''' <param name="cmdText"></param>
    ''' <param name="cmdType"></param>
    ''' <param name="paras">传入参数</param>
    ''' <returns></returns>返回DataTable
    ''' <remarks></remarks>
    Public Function ExecDataTable(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal paras As SqlParameter()) As DataTable
        Dim sqlAdapter As SqlDataAdapter
        Dim dt As New DataTable
        Dim ds As New DataSet


        cmd.CommandText = cmdText
        cmd.CommandType = cmdType
        cmd.Connection = conn
        cmd.Parameters.AddRange(paras) '参数添加


        sqlAdapter = New SqlDataAdapter(cmd) '实例化adapter
        Try
            sqlAdapter.Fill(ds)
            dt = ds.Tables(0)
            cmd.Parameters.Clear()
        Catch ex As Exception
            MsgBox("登录失败")
        Finally
            Call CloseCmd(cmd)
        End Try
        Return dt
    End Function
#End Region

#Region "关闭命令,关闭连接"
    Public Sub CloseCmd(ByVal cmd As SqlCommand)
        If Not IsNothing(cmd) Then '判断是否为空
            cmd.Dispose() '销毁
            cmd = Nothing
        End If
    End Sub

    Public Sub CloseConnection(ByVal conn As SqlConnection)
        If Not IsNothing(conn.State <> ConnectionState.Closed) Then
            conn.Close()
            conn = Nothing
        End If
    End Sub
#End Region
End Class

【UI】

Imports BLL.LoginBLL
Imports Entity.LoginEntity
Imports Facade.LoginFacade

Public Class LoginUI

    Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click

        If txtUserID.Text = "" Then
            MsgBox("用户名不能为空!")
            txtUserID.Focus()
            Exit Sub
        ElseIf txtPwd.Text = "" Then
            MsgBox("密码不能为空!")
            txtPwd.Text = ""
            txtPwd.Focus()
            Exit Sub
        End If

        Try
            '定义一个外观层对象

            Dim facadeLogin As New Facade.LoginFacade
            Dim UserInfo As New Entity.LoginEntity()

            '将文本框中的值传给实体层对象让他带上参数
            UserInfo.UserID = txtUserID.Text
            UserInfo.PassWord = txtPwd.Text

            Dim strResult As Boolean
            strResult = facadeLogin.CheckUser(UserInfo) '将U层文本框的内容传入外观层,然后通过外观层传入b层

            If strResult = False Then
                MsgBox("用户不存在!")
                txtUserID.Text = ""
                txtPwd.Text = ""
                txtPwd.Select()
                txtUserID.Focus()
            End If

            Dim table As DataTable
            table = facadeLogin.CheckPWD(UserInfo)
            If Trim(txtPwd.Text) = Trim(table.Rows(0).Item(1)) Then
                MsgBox("登录成功!")
                txtUserID.Text = ""
                txtPwd.Text = ""
            End If
        Catch ex As Exception
            MsgBox("用户不存在或密码不正确!")
            txtUserID.Text = ""
            txtPwd.Text = ""
            txtUserID.Select() '选中控件中的文本
            txtUserID.Focus()
        End Try
    End Sub

End Class


【Facade】


Imports BLL
Imports Entity

Public Class LoginFacade
    Public Function CheckUser(ByVal UserInfo As Entity.LoginEntity) As Boolean
        Dim isUserExists As New BLL.LoginBLL()
        Dim flag As Boolean
        flag = isUserExists.ExistUser(UserInfo)
        If flag = True Then
            Return True
        Else
            Return False
        End If

    End Function

    Public Function CheckPWD(ByVal UserInfo As Entity.LoginEntity) As DataTable
        Dim isPwdRight As New BLL.LoginBLL()
        Dim table As DataTable
        table = isPwdRight.RightPWD(UserInfo)
        Return table
    End Function

End Clas


【BLL】

Imports IDAL

Public Class LoginBLL
    Public Function ExistUser(ByVal UserInfo As Entity.LoginEntity) As Boolean
        Dim fa As New Factory.LoginFactory()
        Dim Iuser As IDAL.ILoginDAL
        '调用“创建用户”的工厂方法
        Iuser = fa.CreateUserInfo
        Dim table As DataTable
        Dim flag As Boolean
        table = Iuser.selectUser(UserInfo)
        If table.Rows(0).Item(0) = 0 Then  '表中的第一行第一列
            flag = False
        Else
            flag = True
        End If
        Return flag
    End Function

    Public Function RightPWD(ByVal UserInfo As Entity.LoginEntity) As DataTable
        Dim fa As New Factory.LoginFactory()
        Dim Iuser As IDAL.ILoginDAL
        Dim dt As DataTable

        Iuser = fa.CreateUserInfo
        dt = Iuser.selectUser(UserInfo)
        Return dt
    End Function

End Class


【Factory】

Imports System.Configuration '添加对配置文件的引用
Imports System.Reflection  '添加对反射的引用
Imports IDAL

Public Class LoginFactory
    Private Shared ReadOnly AssemblyName As String = "DAL"

    'Private Shared db As String = ConfigurationManager.AppSettings("strConnection")
    Dim db As String = System.Configuration.ConfigurationManager.AppSettings("DB")

    Public Function CreateUserInfo() As ILoginDAL
        'Dim className As String = AssemblyName + "." + db + "LoginDAL" 'DAL层的类名
        Dim className As String = AssemblyName + "." + "LoginDAL" 'DAL层的类名
        Dim iUser As ILoginDAL
        iUser = CType(Assembly.Load(AssemblyName).CreateInstance(className), ILoginDAL) '通过接口去调用D层实现接口中的方法,返回的是接口的实例化对象
        Return iUser
        '这里略写了

    End Function

End Class


【IDAL】

'**************************  
'文 件 名:ILoginDAL  
'命名空间:IDAL 
'内    容:  
'功    能:  
'文件关系:  
'作    者:陈丹  
'小    组:陈丹  
'生成日期:2015.12.21 19:18
'版 本 号:V1.0.0.0  
'修改日志:  
'版权说明:  
'***************************  

Imports Entity.LoginEntity

Public Interface ILoginDAL
    'UserInfo是实体实例化的对象,用来传值
    '接口定义了一个查找用户的方法,用于在数据库中查找用户

    Function selectUser(ByVal UserInfo As Entity.LoginEntity) As DataTable


End Interface


【DAL】

'**************************  
'文 件 名:sqlHelper  
'命名空间:SQLHelper  
'内    容:  
'功    能:  
'文件关系:  
'作    者:陈丹  
'小    组:陈丹  
'生成日期:2015.12.22 10:11
'版 本 号:V1.0.0.0  
'修改日志:  
'版权说明:  
'*************************** 

Imports System.Data.SqlClient '命名空间
Imports Entity
Imports IDAL
'Imports System.Configuration
Imports SQLHelper

Public Class LoginDAL : Implements IDAL.ILoginDAL '实现接口中定义的方法

    Public Function selectUser(UserInfo As LoginEntity) As DataTable Implements ILoginDAL.selectUser
        
        Dim sqlhelper As New SQLHelper.sqlHelper
        Dim cmdType As CommandType = New CommandType()
        Dim paras As SqlParameter() = {New SqlParameter("@UserID", UserInfo.UserID), New SqlParameter("@password", UserInfo.PassWord)}
        Dim cmdText As String
        cmdText = "select * from User_Info where userID=@UserID and passWord=@password"

        'cmdType = CommandType.StoredProcedure '定义命令方式为存储过程
        Dim dt As New DataTable
        dt = sqlhelper.ExecDataTable(cmdText, CommandType.Text, paras)
        Return dt
    End Function
End Class


总结

我们总是惧怕一个看上去很困难的事情,于是拖延症就出现了,其实把大的目标划分成小目标,逐个击破,这件事情就会变得很简单,就像跑马拉松一样,在重构机房的这条道路上,给自己多设几个终点站,这是我的第二站七层登录实现,下一个小目标就是完成修改密码~加油,学习是一个过程,困难是必然会出现的,困难就是为了让我们能看到自己有什么不足的地方,做不到的地方不管是查资料还是请教别人,不管用什么方法,坚信这个困难是绝对可以解决的,不要想那么多就好了!!~~~ 登录磨叽了小一个星期,这条线在调错改错的过程中日渐清晰明朗,希望下个一个站点我可以快快的到达!~


你可能感兴趣的:(机房重构:三层到七层)