一、前言:
从最初C#版的三层,到VB.NET版的三层,最后再到VB.NET版的七层。可谓是历经了不少的曲折经历。刚开始不知如何下手,各种查资料,各种蒙圈,慢慢的终于有了些眉目。只要坚持,先从简单地代码入手,最终程序的大体轮廓,也就呼之欲出啦。
二、七层结构:
七层是在三层的基础上演化而来的,也就是在三层的基础上增加了外观层(Facade)、工厂层(Factory)、和接口层(IDAL)。七层的使用使程序之间的耦合性进一步降低,以便于设计出可扩展、易维护的优质程序。
根据上图添加各层之间的引用关系。接下来就是七层登录的相关代码:
UI层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Imports Entity
Imports Facade
Public Class frmLogin
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
'文本框是否为空
If txtUserName.Text = "" Then
MsgBox("请输入用户名!")
txtUserName.Focus()
Exit Sub
End If
If IsNumeric(txtUserName.Text) = False Then
MsgBox("用户名请输入数字!")
txtUserName.Text = ""
Exit Sub
End If
If txtPassword.Text = "" Then
MsgBox("请输入密码!")
txtPassword.Focus()
Exit Sub
End If
Try
'实例化外观层和实体层
Dim Facade As New Facade.LoginFacade
Dim UserInfo As New Entity.LoginEntity
UserInfo.UserName = txtUserName.Text.Trim
UserInfo.Password = txtPassword.Text.Trim
Dim strResult As Boolean 'strResult为布尔值,返回类型是布尔类型
'将U层的信息传入外观层,然后再由外观层进入B层进行判断
'检验用户名是否正确
strResult = Facade.CheckUser(UserInfo)
'实例化DataTable,DataTable是一个虚拟的表
Dim table As DataTable
'检验密码是否正确
table = Facade.CheckPwd(UserInfo)
Me.Hide()
frmMain.Show()
Catch ex As Exception
MsgBox("用户名或密码错误")
txtPassword.Text = ""
txtUserName.Text = ""
End Try
End Sub
End Class</span></span></span></span>
Facade层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Public Class LoginFacade
'检查用户是否存在
Public Function CheckUser(ByVal UserInfo As Entity.LoginEntity) As Boolean '返回类型也应该是布尔类型
'实例化B层
Dim IsUserExists As New BLL.LoginBLL
Dim flag As Boolean 'flag类型是布尔值
'用户名是否存在
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 '返回类型是DataTable
Dim table As DataTable
'实例化B层,
Dim IsPwdExists As New BLL.LoginBLL
table = IsPwdExists.RightPWD(UserInfo)
Return table
End Function
End Class</span></span></span></span>
BLL层
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Public Class AddUserBLL
Public Function ExistID(ByVal AddUserInfo As Entity.AddUserEntity) As Boolean
Dim table As New DataTable
Dim flag As Boolean
Dim factory As New Factory.AddUserFactory
Dim IID As IDAL.AddUserIDAL
Dim int As Integer
'运用工厂,创建接口
IID = factory.CreateIID
'去实现这个接口
table = IID.selectID(AddUserInfo)
If table.Rows.Count = 0 Then
flag = False
int = IID.AddUserData(AddUserInfo)
MsgBox("添加用户成功!", , "提示")
Else
flag = True
MsgBox("用户ID不能重复添加!", , "提示")
End If
Return flag
End Function
End Class
</span></span></span></span>
Factory层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Imports System.Reflection '添加对反射的引用
Imports System.Configuration '添加对配置文件的引用
Imports System.Data
Imports IDAL
'反射+配置文件+抽象工厂
Public Class LoginFactory
Private Shared ReadOnly AssemblyName As String = "DAL" '程序集名称
'Dim db As String = System.Configuration.ConfigurationSettings.AppSettings("DB")
Public Function CreateIUser() As LoginIDAL '提供创建对象的接口
Dim classname As String = "DAL" + "." + "LoginDAL" '要实例化的D层的类的名称
Dim IUser As LoginIDAL
'CType函数将返回表达式显示的转换为指定的数据类型、对象、结构、类或接口后的结果
IUser = CType(Assembly.Load(AssemblyName).CreateInstance(classname), LoginIDAL) '返回loginIDAL
Return IUser
End Function
End Class
</span></span></span></span>
IDAL层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Public Interface LoginIDAL
'判断用户名是否存在
Function selectUser(ByVal UserInfo As Entity.LoginEntity) As DataTable
End Interface
</span></span></span></span>
DAL层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Imports System.Data.SqlClient 'system.Data.sqlClient命名空间是SQLServer的.NET Framework数据提供程序
'SQL Server的.NET Framework数据提供程序描述了一个类集合,这个类集合用于访问托管空间中的SQL Server数据库
Imports Entity
Imports IDAL
Imports SQLhelper
Public Class LoginDAL : Implements IDAL.LoginIDAL '实现接口
Dim sqlHelper As New SQLhelper.sqlhelper
'判断用户名是否存在
Public Function selectUser(UserInfo As LoginEntity) As DataTable Implements LoginIDAL.selectUser '实现接口
Dim sql As String '中间变量,用于储存从数据库中查找的信息
Dim table As DataTable '声明一个DataTable
'声明并实例化参数数组
Dim sqlParams As SqlParameter() = {New SqlParameter("@UserName", UserInfo.UserName),
New SqlParameter("@Password", UserInfo.Password)}
sql = "select * from User_info where UserID=@UserName and Password=@Password"
'调用SqlHelper类中的GetDataTable()方法来执行查询,并获取返回值
table = sqlHelper.ExecSelect(sql, CommandType.Text, sqlParams)
Return table
End Function
End Class
</span></span></span></span>
SQLHelper层:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Imports System.Data
Imports System.Data.SqlClient
'Imports System.Configuration '引入配置文件命名空间必须在管理器中添加引用.
Public Class sqlhelper
' Dim strConnction As String = ConfigurationManager.AppSettings("connstring")
Dim strConnction As String = Configuration.ConfigurationManager.AppSettings("connstring")
'Dim strConnction As String = "Server=.;Database=chargeRe_sys;User ID=sa;Password=123456"
Dim conn As New SqlConnection(strConnction)
Dim cmd As New SqlCommand
'Exec=execute '执行
Public Function ExecSelect(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal paras As SqlParameter()) As DataTable
Dim sqlAdapter As SqlDataAdapter '定义数据适配器
Dim table As New DataTable
Dim dset As New DataSet
'给cmd赋值
cmd.CommandText = cmdText 'cmdText为所要执行的sql语句
cmd.CommandType = cmdType '命令执行的类型
cmd.Connection = conn
cmd.Parameters.AddRange(paras) '参数添加
sqlAdapter = New SqlDataAdapter(cmd) '实例化Adapter
Try
conn.Open()
sqlAdapter.Fill(dset) '用adapter将dataset填充
table = dset.Tables(0) '
cmd.Parameters.Clear() '清除参数
Catch ex As Exception
MsgBox("数据库操作")
End Try
Return table
End Function</span></span></span></span>
三、配置文件:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="DB" value="sqlserver"/>
<add key="connstring" value="Server=.;Database=chargeRe_sys;User ID=sa;Password=123456"/>
</appSettings>
</configuration</span>
></span></span></span>
四、常见问题:
一、未处理NullReferenceException
更改生成输出路径:DAL——属性——编译——浏览。
反射的一个原则是:一切皆以UI层的bin文件夹中的dll名称为中心,说白一点,dll就是一个类库。我理解的反射,就是一串拼接的字符串,组成要实例化的类的名字。使用反射加载类时,默认是从UI层中的bin中找的,所以要在UI的bin文件夹下生成D层类的dll,这样才能顺利加载。
①未使用New初始化对象:我们在定义一个实体对象或其他对象时,有时因为疏忽,会少写了New。
②反射+工厂+配置文件有错误:Classname应该是程序名.类名(应符合规范反射规范)