解析三层架构(2)----分层究竟分出了那些东西

本文通过对比未分层和分层的代码示例,详细解释了软件分层架构的重要性。介绍了如何将数据库操作提取到DAO层,并通过BLL层进行业务逻辑处理,最后在UI层展示结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上篇文章写到我们为什么要分层.有很多读者提出来很多宝贵的意见.让我受益匪浅,深深的感觉到自己的水平"还有很大的提升空间".首先感谢这些朋友们,我会进一步总结完善自己的想法.

截取了部分朋友的留言,感谢他们:

clip_image001

clip_image002

clip_image003

这次我用对比的方式描述一下,分层到底分出了什么.俗话说:有分必有合,那么它是把什么合到了一起.

首先写出两个没有分层的demo:

<1>查询信息demo

   1: Public Class Form2
<!--CRLF-->
   2:     Private sqlCon As String = "Data Source=LSH;Initial Catalog=ComputerLab;User ID=sa;Password=123456"
<!--CRLF-->
   3:     '查询数据库信息信息
<!--CRLF-->
   4:     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
<!--CRLF-->
   5: 
<!--CRLF-->
   6:         Dim conStr As New SqlConnection '数据库连接对象
<!--CRLF-->
   7:         Dim sqlCom As SqlCommand        '数据库执行对象
<!--CRLF-->
   8:         Dim Res As DialogResult         '消息提示框返回类型
<!--CRLF-->
   9:         Dim dr As SqlDataReader         'dataReader对象
<!--CRLF-->
  10:         Dim dt As New DataTable         'Datatable对象
<!--CRLF-->
  11: 
<!--CRLF-->
  12:         Dim sql As String = "select * from TableName where Name=@name"                   'sql插入语句
<!--CRLF-->
  13:         conStr.ConnectionString = sqlCon                                '给数据库连接对象赋值
<!--CRLF-->
  14:         sqlCom = New SqlCommand(sql, conStr)                            '给数据库执行对象赋值
<!--CRLF-->
  15:         sqlCom.Parameters.Add("@name", SqlDbType.VarChar, TextBox1.Text)    '给sql语句参数赋值
<!--CRLF-->
  16: 
<!--CRLF-->
  17:         Res = MessageBox.Show("是否添加", "提示", MessageBoxButtons.OKCancel)
<!--CRLF-->
  18:         '判断是否查询
<!--CRLF-->
  19:         If Res = DialogResult.Yes Then
<!--CRLF-->
  20:             Try
<!--CRLF-->
  21:                 conStr.Open()
<!--CRLF-->
  22:                 dr = sqlCom.ExecuteReader    '执行查询语句
<!--CRLF-->
  23:                 dt.Load(dr)
<!--CRLF-->
  24:             Catch ex As Exception
<!--CRLF-->
  25:                 Throw ex
<!--CRLF-->
  26:             Finally
<!--CRLF-->
  27:                 If Not IsNothing(conStr) Then   '如果数据库打开,则关闭数据库
<!--CRLF-->
  28:                     conStr.Close()
<!--CRLF-->
  29:                 End If
<!--CRLF-->
  30:             End Try
<!--CRLF-->
  31:         End If
<!--CRLF-->
  32: 
<!--CRLF-->
  33:         MsgBox(dt.Rows.Count)   '显示查询到的行数
<!--CRLF-->
  34:     End Sub
<!--CRLF-->
 
  
<2>添加信息demo
   1: Public Class Form1
<!--CRLF-->
   2:     Private sqlCon As String = "Data Source=LSH;Initial Catalog=ComputerLab;User ID=sa;Password=123456"
<!--CRLF-->
   3:     '向数据库添加信息
<!--CRLF-->
   4:     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
<!--CRLF-->
   5:         Dim bln As Boolean = False      '存储返回值
<!--CRLF-->
   6:         Dim conStr As New SqlConnection '数据库连接对象
<!--CRLF-->
   7:         Dim sqlCom As SqlCommand        '数据库执行对象
<!--CRLF-->
   8:         Dim Res As DialogResult         '消息提示框返回类型
<!--CRLF-->
   9: 
<!--CRLF-->
  10:         Dim sql As String = "insert into TableName(Name) value(@Name)"  'sql插入语句
<!--CRLF-->
  11:         conStr.ConnectionString = sqlCon                                '给数据库连接对象赋值
<!--CRLF-->
  12:         sqlCom = New SqlCommand(sql, conStr)                            '给数据库执行对象赋值
<!--CRLF-->
  13:         sqlCom.Parameters.Add("@Name", SqlDbType.VarChar, TextBox1.Text) '给sql语句参数赋值
<!--CRLF-->
  14: 
<!--CRLF-->
  15:         Res = MessageBox.Show("是否添加", "提示", MessageBoxButtons.OKCancel)
<!--CRLF-->
  16:         '判断是否同意插入
<!--CRLF-->
  17:         If Res = DialogResult.Yes Then
<!--CRLF-->
  18:             Try
<!--CRLF-->
  19:                 conStr.Open()
<!--CRLF-->
  20:                 bln = sqlCom.ExecuteNonQuery    '执行插入语句
<!--CRLF-->
  21:             Catch ex As Exception
<!--CRLF-->
  22:                 bln = False
<!--CRLF-->
  23:             Finally
<!--CRLF-->
  24:                 If Not IsNothing(conStr) Then   '如果数据库打开,则关闭数据库
<!--CRLF-->
  25:                     conStr.Close()
<!--CRLF-->
  26:                 End If
<!--CRLF-->
  27:             End Try
<!--CRLF-->
  28:         End If
<!--CRLF-->
  29: 
<!--CRLF-->
  30:         MsgBox(bln) '提示返回信息
<!--CRLF-->
  31:     End Sub
<!--CRLF-->
  32: End Class
<!--CRLF-->
<!--CRLF-->
<!--CRLF-->

上面的两个没有分层的代码,当然在功能的实现上是完全没有问题.但是这样设计带来了很多的危机:

(1):写这个模块的人必须是一个能力非常强的人,因为他需要操作数据库,理解业务逻辑

(2):如果有另为一个模块需要这两个操作数据库的方法,只能重写或者调用该窗体下的方法.

(3):如果业务逻辑稍有变动,就需要拆开这个模块,重新编写,对于重新设计的人来说这个模块的所有设计都是可见的,很是不安全.

(4):如果要更换或者改动数据库,结果就是每一个模块都要重新编写

(5):如果有另为一个和这个相似的工程,想要复用以前的东西,难度很大

对于一个公司来说,当然不希望发生这样的事情.所以,合理的分层,降低系统的耦合性是必要的.

第一步:把数据库操作提取出来.

对每一个表,把完全对他的操作单独写成类也就是我们的DAO,数据访问类

每一个表对应一个DAO,每个DAO里面包含该数据库的所有增,删,查,改操作.这样做的好处就是对数据库的操作完全独立,达到功能单一.降低了和其他模块的耦合,写代码的时候,程序员不需要了解业务逻辑.

而且,在维护上和扩展上,如果对数据库改动,就会有针对性的去修改DAO.

当然,在设计的时候,我们尽量去封装不变的操作,这样不但能减少代码量,而且能达到很好的复用效果.在数据库操作中,对于数据库的打开,执行,关闭基本上都是一样的.所以我们单独提取出来sqlHelper(数据库助手类)

   1: Imports System.Data.SqlClient
<!--CRLF-->
   2: Imports System.Configuration
<!--CRLF-->
   3: 
<!--CRLF-->
   4: ''' <summary>
<!--CRLF-->
   5: ''' 运行数据库
<!--CRLF-->
   6: ''' </summary>
<!--CRLF-->
   7: Public Class SqlHelp
<!--CRLF-->
   8:     Private cmd As SqlCommand   'sqlcommand对象
<!--CRLF-->
   9:     Private con As SqlConnection    'sqlconnection对象
<!--CRLF-->
  10:     Private dr As SqlDataReader     'sqlDataReader对象
<!--CRLF-->
  11:     ''' <summary>
<!--CRLF-->
  12:     ''' 获取连接字符串
<!--CRLF-->
  13:     ''' </summary>
<!--CRLF-->
  14:     ''' <returns>连接字符串</returns>
<!--CRLF-->
  15:     ''' <remarks></remarks>
<!--CRLF-->
  16:     Public Function GetCon() As SqlConnection
<!--CRLF-->
  17:         Dim conStr As String
<!--CRLF-->
  18:         conStr = System.Configuration.ConfigurationManager.AppSettings("ConnStr")
<!--CRLF-->
  19: 
<!--CRLF-->
  20:         con = New SqlConnection
<!--CRLF-->
  21:         con.ConnectionString = conStr
<!--CRLF-->
  22: 
<!--CRLF-->
  23:         '打开数据库
<!--CRLF-->
  24:         If (con.State = ConnectionState.Closed) Then
<!--CRLF-->
  25:             con.Open()
<!--CRLF-->
  26:         End If
<!--CRLF-->
  27: 
<!--CRLF-->
  28:         Return con
<!--CRLF-->
  29: 
<!--CRLF-->
  30:     End Function
<!--CRLF-->
  31: 
<!--CRLF-->
  32:     ''' <summary>
<!--CRLF-->
  33:     ''' 增 删 改方法
<!--CRLF-->
  34:     ''' </summary>
<!--CRLF-->
  35:     ''' <param name="sqlStr">数据库语句 活存储过程名</param>
<!--CRLF-->
  36:     ''' <param name="Param">参数数组</param>
<!--CRLF-->
  37:     ''' <param name="commandType">数据库字符串 或者存储过程名 类型</param>
<!--CRLF-->
  38:     Public Function ExecuteNonQuery(ByVal sqlStr As String, ByVal Param() As SqlParameter, ByVal commandType As CommandType) As Boolean
<!--CRLF-->
  39: 
<!--CRLF-->
  40:         cmd = New SqlCommand(sqlStr, Me.GetCon)
<!--CRLF-->
  41:         cmd.CommandType = commandType
<!--CRLF-->
  42: 
<!--CRLF-->
  43:         '添加参数
<!--CRLF-->
  44:         If Param IsNot Nothing Then
<!--CRLF-->
  45:             cmd.Parameters.AddRange(Param)
<!--CRLF-->
  46:         End If
<!--CRLF-->
  47: 
<!--CRLF-->
  48:         '执行语句
<!--CRLF-->
  49:         Try
<!--CRLF-->
  50:             Return CBool(cmd.ExecuteNonQuery)
<!--CRLF-->
  51:         Catch ex As Exception
<!--CRLF-->
  52:             Return False
<!--CRLF-->
  53:         Finally
<!--CRLF-->
  54:             If Not IsNothing(con) Then
<!--CRLF-->
  55:                 con.Close()
<!--CRLF-->
  56:             End If
<!--CRLF-->
  57:         End Try
<!--CRLF-->
  58: 
<!--CRLF-->
  59:     End Function
<!--CRLF-->
  60: 
<!--CRLF-->
  61:     ''' <summary>
<!--CRLF-->
  62:     ''' 查询
<!--CRLF-->
  63:     ''' </summary>
<!--CRLF-->
  64:     ''' <param name="sqlStr">sql语句 或者存储过程名</param>
<!--CRLF-->
  65:     ''' <param name="Param">参数数组</param>
<!--CRLF-->
  66:     ''' <param name="commandType">执行类型</param>
<!--CRLF-->
  67:     Public Function ExecuteQuery(ByVal sqlStr As String, ByVal Param() As SqlParameter, ByVal commandType As CommandType) As DataTable
<!--CRLF-->
  68:         Dim dt As New DataTable
<!--CRLF-->
  69:         cmd = New SqlCommand(sqlStr, Me.GetCon)
<!--CRLF-->
  70:         cmd.CommandType = commandType
<!--CRLF-->
  71: 
<!--CRLF-->
  72:         '添加参数
<!--CRLF-->
  73:         If Param IsNot Nothing Then
<!--CRLF-->
  74:             cmd.Parameters.AddRange(Param)
<!--CRLF-->
  75:         End If
<!--CRLF-->
  76: 
<!--CRLF-->
  77:         '执行语句
<!--CRLF-->
  78:         Try
<!--CRLF-->
  79:             dr = cmd.ExecuteReader
<!--CRLF-->
  80:             dt.Load(dr)
<!--CRLF-->
  81:         Catch ex As Exception
<!--CRLF-->
  82:             Return Nothing
<!--CRLF-->
  83:         Finally
<!--CRLF-->
  84:             If Not IsNothing(con) Then
<!--CRLF-->
  85:                 con.Close()
<!--CRLF-->
  86:             End If
<!--CRLF-->
  87:         End Try
<!--CRLF-->
  88:         Return dt
<!--CRLF-->
  89:     End Function
<!--CRLF-->
提取后数据库访问层代码如下: 
   1: Imports SqlHelper
<!--CRLF-->
   2: Imports System.Data.SqlClient
<!--CRLF-->
   3: Public Class DAL
<!--CRLF-->
   4:     Private sqlHelper As New SqlHelp
<!--CRLF-->
   5:     ''' <summary>
<!--CRLF-->
   6:     ''' 查询记录
<!--CRLF-->
   7:     ''' </summary>
<!--CRLF-->
   8:     ''' <param name="strSelect">关键字</param>
<!--CRLF-->
   9:     ''' <returns>记录集</returns>
<!--CRLF-->
  10:     ''' <remarks></remarks>
<!--CRLF-->
  11:     Public Function SelectInfo(ByVal strSelect As String) As DataTable
<!--CRLF-->
  12:         'sql查询语句
<!--CRLF-->
  13:         Dim sql As String = "select * from TableName where Name=@name"
<!--CRLF-->
  14:         '向sql参数中添加实参
<!--CRLF-->
  15:         Dim Para() As SqlParameter = {New SqlParameter("@name", strSelect)}
<!--CRLF-->
  16:         '调用sqlhelper执行数据库操作
<!--CRLF-->
  17:         Return sqlHelper.ExecuteQuery(sql, Para, Data.CommandType.Text)
<!--CRLF-->
  18:     End Function
<!--CRLF-->
  19:     ''' <summary>
<!--CRLF-->
  20:     ''' 添加记录
<!--CRLF-->
  21:     ''' </summary>
<!--CRLF-->
  22:     ''' <param name="strAdd">记录信息</param>
<!--CRLF-->
  23:     ''' <returns>是否成功</returns>
<!--CRLF-->
  24:     ''' <remarks></remarks>
<!--CRLF-->
  25:     Public Function AddInfo(ByVal strAdd As String) As Boolean
<!--CRLF-->
  26:         'sql插入语句
<!--CRLF-->
  27:         Dim sql As String = "insert into TableName(Name) value(@Name)"
<!--CRLF-->
  28:         '向sql参数中添加实参
<!--CRLF-->
  29:         Dim Para() As SqlParameter = {New SqlParameter("@name", strAdd)}
<!--CRLF-->
  30:         '调用sqlhelper执行数据库操作
<!--CRLF-->
  31:         Return sqlHelper.ExecuteNonQuery(sql, Para, Data.CommandType.Text)
<!--CRLF-->
  32:     End Function
<!--CRLF-->
  33: End Class
<!--CRLF-->
<!--CRLF-->

第二:根据业务逻辑,个人习惯和用例相对应,把相关的逻辑判断,比如添加记录在什么情况下判断,添加前要判断记录是否存在等放到BLL层.

但是对于数据的有效性校验一般还是放在UI层,也可以有其他更好的方法,这些我在以后会总结出来.

代码如下:

   1: Public Class BLL
<!--CRLF-->
   2:     Private dal As New DAL
<!--CRLF-->
   3:     ''' <summary>
<!--CRLF-->
   4:     ''' 业务逻辑层,添加方法
<!--CRLF-->
   5:     ''' </summary>
<!--CRLF-->
   6:     ''' <param name="strAdd">添加信息</param>
<!--CRLF-->
   7:     ''' <remarks></remarks>
<!--CRLF-->
   8:     Public Sub Add(ByVal strAdd As String)
<!--CRLF-->
   9:         '定义用于存储查询结果的记录集
<!--CRLF-->
  10:         Dim dt As New DataTable
<!--CRLF-->
  11:         '执行查询,判断添加的信息是否已经存在
<!--CRLF-->
  12:         dt = dal.SelectInfo(strAdd)
<!--CRLF-->
  13:         If dt.Rows.Count > 0 Then
<!--CRLF-->
  14:             Throw New Exception("记录已存在")
<!--CRLF-->
  15:         Else
<!--CRLF-->
  16:             '添加记录,返回是否成功
<!--CRLF-->
  17:             If dal.AddInfo(strAdd) = True Then
<!--CRLF-->
  18:                 Throw New Exception("添加成功")
<!--CRLF-->
  19:             Else
<!--CRLF-->
  20:                 Throw New Exception("添加失败")
<!--CRLF-->
  21:             End If
<!--CRLF-->
  22:         End If
<!--CRLF-->
  23: 
<!--CRLF-->
  24:     End Sub
<!--CRLF-->
  25: 
<!--CRLF-->
  26: End Class
<!--CRLF-->
第三:剩下的UI层里,除了判断数据有效性以为,只要调用bll的添加方法就可以了.这样制作UI的人就会减轻了很大的压力,让他们专心做美工或者其他.

代码如下:

   1: Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
<!--CRLF-->
   2:         Dim bll As New BLL
<!--CRLF-->
   3:         '调用bll层添加方法
<!--CRLF-->
   4:         Try
<!--CRLF-->
   5:             bll.Add(TextBox1.Text)
<!--CRLF-->
   6:         Catch ex As Exception
<!--CRLF-->
   7:             '显示添加结果给用户
<!--CRLF-->
   8:             MessageBox.Show(ex.Message)
<!--CRLF-->
   9:         End Try
<!--CRLF-->
  10:     End Sub
<!--CRLF-->
<!--CRLF-->

当然三层方式还有其他一些技巧,比如为DAL加一层接口,用抽象工厂加反射的方法实现数据库的灵活操作,替换.这里先不叙述.

上述都是个人的一点总结,欢迎大家指导

接下文:解析三层架构(3)--实体类与面向对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值