七层登陆的华丽转身

来源:互联网 发布:淘宝男裤子店铺排名 编辑:程序博客网 时间:2024/04/30 03:08

概述        

       三层结构主要体现出对程序分而治之的思想:数据访问层只负责提供原始数据,并不需要了解业务逻辑;业务逻辑层调用数据访问层提供的方法自定义一些业务逻辑,对数据进行加工,本身不需要了解数据访问层的实现;表示层直接调用业务逻辑提供的方法把数据呈现给用户。而为了更好的追求面向对象的高内聚和低耦合,加入适当的设计模式是必不可少的。通过对设计模式中抽象工厂和外观模式的应用,将三层架构的登陆进行升级和扩充,也就是变成了现在的七层。

          具体的架构和关系如图所示


如图,该七层登陆使用了表现层UI、外观层Facade、业务逻辑层BLL、数据接口层IDAL、数据访问层DAL、工厂层Factory、实体层Entity和数据库操作组件类SQLHelper共同组成。

实体层Entity

       实体类,在我一开始接触三层的时候以为它就是三层的一层,通过不断的加深理解,认识到实体层的存在是为了在各层之间起到一个数据传输的作用。我们知道,实体层是定义属性的,而这些属性就是数据库中我们所用到的字段。但是,直到读了一个文档,才知道,实体类什么也不是!它在三层架构中是可有可无的。它其实就是面向对象编程中最基本的东西:类。它在三层架构中的位置,和Int,string等变量的地位是一样的,没有其他的目的,仅仅是为了用于数据存储而已,只不过它存储的是复杂的数据。所以,如果你的项目非常简单,不用实体类而直接传递多个参数也是可以的。
       但是,为什么我要还是要使用实体类呢?我们可以通过具体的应用来看:
在各层传递参数时,可以这样:
AddUser(userId,userName,userPassword,…,)
也可以这样:
AddUser(userInfo)
这两种方法那个好呢。一目了然,肯定是第二种要好很多。所以当我们要传递的参数非常多的时候,使用实体类会大大减少我们的工作量。


外观模式

        外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一个子系统更加容易使用。
在曾与层之间建立外观层Facade,这样可以为复杂的子系统提供一个简单的接口,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖。
               


抽象工厂

        抽象工厂模式:提供一个创建一系列相关或相互依赖的接口,而无需指定他们具体的类。用反射+配置文件实现数据访问程序。这样就能更加的符合开放-封闭的原则,将抽象工厂的优点完全发挥出来。
         下面让我们看一看配置文件的代码:
<?xml version="1.0" encoding="utf-8" ?><configuration>     <connectionStrings>      <add name ="ConnString" connectionString ="Data Source=DESKTOP-F8291CO;Initial Catalog=Login;User ID=sa;Password=123456"/>  </connectionStrings>  <appSettings>  <clear/>  <add key="DBString" value="Sql server"/> </appSettings></configuration>

代码实现

      通过上述所述,三层架构结合设计模式,最终生成的解决方案如图所示:

                  

SQLHelper

         SqlHelper是一个基于.NET Framework的数据库操作组件。组件中包含数据库操作方法。SqlHelper用于简化你重复的去写那些数据库连接(SqlConnection),SqlCommand,SqlDataReader等等。SqlHelper 封装过后通常是只需要给方法传入一些参数如数据库连接字符串,SQL参数等,就可以访问数据库了,很方便。具体内容详见这里。
Imports System.Data.SqlClientImports System.ConfigurationPublic Class SqlHelper    Dim DBConnectStr As New DALUtil    Dim DBConnection As New SqlConnection(DBConnectStr.ConnectString)    Dim cmd As New SqlCommand    '设置连接    '定义cmd命令    Public Function ExecAddDelUpdate(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal sqlParams As SqlParameter()) As Integer        '将传入的值,分别为cmd的属性赋值          cmd.Parameters.AddRange(sqlParams)   '将参数传入          cmd.CommandType = cmdType            '设置一个值,解释cmdText          cmd.Connection = DBConnection                '设置连接,全局变量          cmd.CommandText = cmdText            '设置查询的语句          Try            DBConnection.Open()                      '打开连接              Return cmd.ExecuteNonQuery()     '执行增删改操作              cmd.Parameters.Clear()           '清除参数          Catch ex As Exception            Return 0                         '如果出错,返回0          Finally            Call CloseConn(DBConnection)            Call CloseCmd(cmd)        End Try    End Function    Public Function ExecAddDelUpdate(ByVal cmdText As String, ByVal cmdType As CommandType) As Integer        '为要执行的命令cmd赋值          cmd.CommandText = cmdText       '先是查询的sql语句          cmd.CommandType = cmdType       '设置Sql语句如何解释          cmd.Connection = DBConnection           '设置连接          '执行操作          Try            DBConnection.Open()            Return cmd.ExecuteNonQuery()        Catch ex As Exception            Return 0        Finally            Call CloseConn(DBConnection)            Call CloseCmd(cmd)        End Try    End Function    Public Function ExecSelect(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal sqlParams As SqlParameter()) As DataTable        '执行查询操作,有参数        Dim adapter As SqlDataAdapter        Dim dt As New DataTable        Dim ds As New DataSet        cmd.CommandText = cmdText        cmd.CommandType = cmdType        cmd.Connection = DBConnection        cmd.Parameters.AddRange(sqlParams)        adapter = New SqlDataAdapter(cmd)        Try            adapter.Fill(ds)            dt = ds.Tables(0)            cmd.Parameters.Clear()        Catch ex As Exception            Throw New Exception("查询失败!")        Finally            Call CloseCmd(cmd)        End Try        Return dt    End Function    Public Function ExecSelect(ByVal cmdText As String, ByVal cmdType As CommandType) As DataTable        '执行查询操作,无参数        Dim adapter As SqlDataAdapter        Dim ds As New DataSet        cmd.CommandText = cmdText        cmd.CommandType = cmdType        cmd.Connection = DBConnection        adapter = New SqlDataAdapter(cmd)        Try            adapter.Fill(ds)            Return ds.Tables(0)        Catch ex As Exception            Return Nothing        Finally            Call CloseCmd(cmd)        End Try    End Function    Public Sub CloseConn(ByVal conn As SqlConnection)        If (conn.State <> ConnectionState.Closed) Then  '如果没有关闭              conn.Close()                    '关闭连接              conn = Nothing                  '不指向原对象          End If    End Sub    Public Sub CloseCmd(ByVal cmd As SqlCommand)        If Not IsNothing(cmd) Then          '如果cmd命令存在              cmd.Dispose()                   '销毁              cmd = Nothing        End If    End SubEnd Class

实体层

Public Class LoginEntity    Private _userName As String    Private _passWord As String    Public Property UserName As String        Get            Return _userName        End Get        Set(value As String)            _userName = value        End Set    End Property    Public Property PassWord As String        Get            Return _passWord        End Get        Set(value As String)            _passWord = value        End Set    End PropertyEnd Class


U层

Imports EntityImports FacadeImports Entity.AllUsePublic Class frmLogin    Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click        Dim fac As New Facade.LoginFacade    '定义一个外观对象        Dim fac1 As New Facade.LoginFacade        Dim dt As DataTable        Dim UserInfo As New Entity.LoginEntity  '定义一个实体类对象        Try            If txtUserName.Text.Trim() = "" Or txtPassWord.Text.Trim() = "" Then                MsgBox("用户ID或密码不可为空", , "警告")            ElseIf IsNumeric(Trim(txtUserName.Text)) = False Then                MsgBox("用户名请输入数字!", , "警告")                txtUserName.Text = ""            Else                UserInfo.UserName = Val(txtUserName.Text.Trim())           '将U层数据传给实体层                UserInfo.PassWord = txtPassWord.Text.Trim()                dt = fac.CheckUser(UserInfo)                If Trim(UserInfo.PassWord) <> dt.Rows(0).Item(1).trim() Then                    MsgBox("密码错误")                    txtPassWord.Text = ""                    txtPassWord.Focus()                Else                                  AllUserID = txtUserName.Text.Trim()                    Me.Hide()                    frmMDImain.Show()                End If            End If        Catch ex As Exception            MsgBox("用户不存在或者密码不正确!")            txtPassWord.Text = ""            txtUserName.Text = ""            txtUserName.Focus()        End Try    End Sub


Facade层

Imports EntityImports BLLImports System.ReflectionPublic Class LoginFacade    Public Function CheckUser(ByVal UserInfo As Entity.LoginEntity) As DataTable        Dim IsUes As New BLL.LoginBLL()        Dim dt As DataTable        dt = IsUes.IsUserExists(UserInfo)        Return dt    End Function

B层

Imports IDALPublic Class LoginBLL     Public Function IsUserExists(ByVal UserInfo As Entity.LoginEntity) As DataTable        Dim fac As New Factory.LoginFactory()        Dim Iuser As IDAL.ILoginDAL                     '调用“创建用户”的工厂方法        Dim dt As DataTable        Iuser = fac.CreateUserInfo        dt = Iuser.SelectUser(UserInfo)        If dt.Rows.Count = 0 Then            MsgBox("没有该用户信息!")        End If        Return dt    End FunctionEnd Class

工厂层

Imports System.Configuration   '添加对配置文件的引用Imports System.Reflection      '添加对反射的引用Imports IDALPublic Class LoginFactory    Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("DBString")    Public Function CreateUserInfo() As IDAL.ILoginDAL        'Ctype是一个内联函数,将前面的部分转化未后半部分        'LoginDAL为程序集名称        'Login.DAL为命名空间名称        'IUserInfoDal为要实例化的“类名”        'CreateUserInfo 创建实例        Return CType(Assembly.Load("DAL").CreateInstance("DAL.LoginSQL"), IDAL.ILoginDAL)    End FunctionEnd Class


接口层

Imports System.ReflectionPublic Interface ILoginDAL    Function SelectUser(ByVal UserInfo As Entity.LoginEntity) As DataTableEnd Interface

D层

Imports System.Data.SqlClientImports EntityImports IDALImports SQLHelperPublic Class LoginSQL : Implements IDAL.ILoginDAL    Public Function SelectUser(UserInfo As LoginEntity) As DataTable Implements ILoginDAL.SelectUser        Dim shelper As New SQLHelper.sqlHelper        Dim cmdType As CommandType = New CommandType()        Dim paras As SqlParameter() = {New SqlParameter("@UserName", UserInfo.UserName), New SqlParameter("@PassWord", UserInfo.PassWord)}        Dim cmdText As String        cmdText = "Select * from Users where UserName=@UserName And PassWord=@PassWord"        Dim dt As New DataTable        dt = shelper.ExecSelect(cmdText, CommandType.Text, paras)        Return dt    End FunctionEnd Class

DALUti类
Public Class DALUtil    'Public Shared Function connstring() As String    '    connstring = "Server=.;Databse=Login;User ID=sa;Password=123456"  '连接SQL的字符串    'End Function    Private ReadOnly db As String = System.Configuration.ConfigurationManager.AppSettings("DBString")  '数据库    Private ReadOnly ConnectStr As String = System.Configuration.ConfigurationManager.ConnectionStrings("ConnString").ToString    'sql数据库连接字符串    Public connectString As String = ConnectStrEnd Class



总结:通过对七层登陆的实现,对整个程序进行单步调试,使得对整个程序的数据流的传递方式和过程更加清晰,对于各个层之间的相互引用也理解的更加深刻,为个人机房重构打下了很好的基础,同时也让我深深的意识到解耦和的重要性,对于三层架构和设计模式的理解和运用也要通过不断地积累和应用来变得更加熟练。通过这几天的学习,让我对面向对象的兴趣越来越大,继续努力吧!


      





6 0