一、前言:
从最初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应该是程序名.类名(应符合规范反射规范)