前言
学习是相通的,学习完三层我们接着是机房重构,这里就需要用七层,因此在学习三层时我们要学会怎么转化成七层
三足鼎立,分而治之。我们可以形象把三层比作三国,层次之间的引用就是结盟,吴蜀之间的结盟,但是魏国是基本不会和这两国进行沟通。这三个国家内部是自己管理,主要政权在自己手里,但是军事需要引用两国的。但是始终避免自己的政权落入其他国家,因此三国之间的依赖并不大。但是历史的更迭是必然的,我们的需求也是不断提高的,七层应运而出。
内容
三层学习之后我们转变成七层的过程使用设计模式的思想,至于为什么要加上这四层就需要我们在下面的学习中了解。
现在加入了四层,其实对于实体层entity已经相当的清楚,主要是为了和数据库表解耦,使要访问的字段都在其中。外观层(facade)作用其实和IDAL层的作用是一样的,就是在考虑数据访问层和业务逻辑层,业务逻辑层和表示层的层与层之间建立外观层,使得复杂的子系统提供一个简单的接口,使得耦合度大大降低。抽象工厂在机房登陆界面上使用的本质是分为了减少数据库的类型之间转换,而使得BLL和DAL层之间的耦合度增加。
七层时为了进一步更好降低耦合度,实现面向对象的高内聚低耦合的,我们在三层中引进了设计模式中的外观和抽象工厂,将三层登陆进行扩充、提高等级。
外观模式:作为我们向外的门面,就像是公司的前台。如果你来公司做某某事,需要和前台进行交流,再由前台联系对应的部门或人员,这样你就不必在公司乱找一通。
Facade定义:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一个子系统更加容易使用。
建立外观层Facade,这样为复杂的子系统提供一个简单的接口,作为子系统的门面,需要使用此系统只需要调用接口,再有接口处理需要的内容,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖。
抽象工厂:提供一组相关或相互依赖对象的接口,而无需指定他们具体的类。可以这么说抽象工厂是随着我们需求不断提高而进化出来的。
现在自主创业的很多,开饭馆的也是遍地开花。由于起初资金有限,自己既当老板,又当厨子,但是顾客刚开始还喜欢你自己做的饭,但是时间长了就发现顾客早就吃腻了很多回头客也不来了,因为他们想吃更多菜,老是那么几个早就烦了。现在就需要跟多风味的菜肴,这时自己是不会做太多了,就需要请厨师帮助了。厨师做的菜很多挽回了很多顾客,但是随着时间的推移,顾客的口味想要换一换,但是这个厨师是川菜的大厨,满足不了顾客的需求,这就需要引进更多菜系的厨师。工厂三姐妹的关系就像是开饭馆,不断发展、不断满足需求。
代码
SQLHelper:就是将数据库的数据表存储在这,在其它层调用DAL时查询语句,通过sqlHelper的DataSet将数据表的查询信息返回给DAL。
<span style="font-family:KaiTi_GB2312;font-size:18px;">Public Class sqlHelper Public Shared Function GetDataTable(ByVal cmdTxt As String, ByVal cmdType As CommandType, ByVal paras As SqlParameter()) As DataTable Dim conn As SqlConnection = New SqlConnection(ConnectionString) '建立数据库连接 Dim cmd As SqlCommand '定义命令变量cmd Dim adaptor As SqlDataAdapter '定义数据适配器 Dim adataset As DataSet '定义并实例化数据缓冲去对象,从数据库传入的对象 cmd = New SqlCommand(cmdTxt, conn) '在conn上执行实例化 命令变量,并执行语句cmdType cmd.CommandType = cmdType '命令执行的类型 cmd.Parameters.AddRange(paras) '命令执行时的参数 adaptor = New SqlDataAdapter(cmd) '净结果绑定到数据适配器 adataset = New DataSet Try '如果数据库连接状态为关闭则将其打开 If conn.State = ConnectionState.Closed Then conn.Open() End If adaptor.Fill(adataset) '向adaptor对象中填充查询的数据 Catch ex As Exception '错误处理程序,出错则提示 MsgBox(ex.Message, , "数据库操作") Finally If conn.State = ConnectionState.Open Then conn.Close() End If End Try Return adataset.Tables(0) '表格形式返回结果 End Function End Class </span>Entity实体层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Public Class ScoreEntity Private strUserName As String '实例化得带用户名和密码 Private strScore As Integer Public Property UserName() As String '设置userName的属性 Get Return strUserName End Get Set(value As String) strUserName = value End Set End Property Public Property Score() As Integer Get Return strScore End Get Set(value As Integer) strScore = value End Set End Property End Class</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;">Public Class LoginUserEntity Private strUserName As String '实例化得到的用户名和密码。 Private strPassword As String Public Property userName() As String '设置userName属性 Get Return strUserName End Get Set(value As String) strUserName = value End Set End Property Public Property password() As String '设置password属性 Get Return strPassword End Get Set(value As String) strPassword = value End Set End Property End Class</span>UI层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports LoginBLL Imports LoginEntity Imports LoginFacade Public Class Form1 Dim ScoreBLL As New LoginBLL.LoginBLL() Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click If txtBox1.Text = "" Then MessageBox.Show("请输入用户名!", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) txtBox1.Text = "" txtBox1.Focus() Exit Sub ElseIf txtBox2.Text = "" Then MessageBox.Show("请输入密码!", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) txtBox2.Text = "" txtBox2.Focus() Exit Sub End If Dim ScoreEntity As New LoginEntity.ScoreEntity() ScoreEntity.Score = 10 ScoreEntity.UserName = txtBox1.Text Try '定义一个外观层的对象 Dim FacadeLogin As New LoginFacade.LoginFacade Dim UserInfo As New LoginEntity.LoginUserEntity() UserInfo.userName = Trim(txtBox1.Text) UserInfo.password = Trim(txtBox2.Text) Dim strResult1 As Boolean strResult1 = FacadeLogin.CheckUser(UserInfo) '将U层的文本框的内容传入外观层,然后通过外观层传入B层进行判断 If strResult1 = False Then MsgBox("用户不存在!") txtBox1.Text = "" txtBox2.Text = "" txtBox1.Select() txtBox1.Focus() End If Dim table As DataTable table = FacadeLogin.CheckPwd(UserInfo) If Trim(txtBox2.Text) = Trim(table.Rows(0).Item(2)) Then ScoreBLL.AddScore(ScoreEntity) MsgBox("登陆成功!") txtBox1.Text = "" txtBox2.Text = "" End If Catch ex As Exception MsgBox("用户不存在或者密码不正确") txtBox1.Text = "" txtBox2.Text = "" txtBox1.Select() txtBox1.Focus() End Try End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load txtBox1.Select() txtBox1.Focus() End Sub End Class </span>Facade外观层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports LoginBLL Imports LoginEntity Public Class LoginFacade Public Function CheckUser(ByVal UserInfo As LoginEntity.LoginUserEntity) As Boolean '用于检查用户是否存在 Dim IsUserExists As New LoginBLL.LoginBLL() Dim flag As Boolean flag = IsUserExists.IsUserExists(UserInfo) If flag = True Then Return True Else Return False End If End Function '检查密码是否正确 Public Function CheckPwd(ByVal UserInfo As LoginEntity.LoginUserEntity) As DataTable Dim IsPwd As New LoginBLL.LoginBLL() Dim table As DataTable table = IsPwd.isPWDright(UserInfo) Return table End Function End Class </span>B层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports LoginBLL Imports LoginEntity </span><pre name="code" class="vb"><span style="font-family:KaiTi_GB2312;font-size:18px;">Public Class LoginBLL '检查用户是否存在 Public Function IsUserExists(ByVal UserInfo As LoginEntity.LoginUserEntity) As Boolean Dim factory As New Factory.LoginFactory 'Dim Iuser As IDAL.IuserinfoDAL Dim Iuser As IDAL.IuserinfoDAL '调用"创建用户"的工厂方法 'Iuser = factory.CreateUserInfo() Iuser = factory.CreateUserInfo Dim table As DataTable ' Dim flag As Boolean Dim flag As Boolean table = Iuser.selectUser(UserInfo) '由于在sqlHelper中返回的形式为表格形式(adataset.Tables(0)),且开头第一列表示为0,所以Item(0)则代表用户名 If table.Rows(0).Item(1) = "" Then flag = False Else flag = True End If Return flag End Function '查看密码是否正确 Public Function isPWDright(ByVal UserInfo As LoginEntity.LoginUserEntity) As DataTable Dim factory As New Factory.LoginFactory() Dim Iuser As IDAL.IuserinfoDAL Dim table As DataTable '中间变量,用于存储D层查询到的数据 Iuser = factory.CreateUserInfo '调用工厂的CreateUserInfo方法创建Iuser接口实例 table = Iuser.selectUser(UserInfo) '调用接口的方法selectUser. Return table End Function Public Function AddScore(score As LoginEntity.ScoreEntity) As Boolean Dim factory As New Factory.LoginFactory() Dim IScore As IDAL.IScore IScore = factory.CreateScoreInfo() Return IScore.UpdateScore(score) End Function End Class </span>
D层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports System.Data.SqlClient Imports LoginEntity Imports IDAL '************************** '文 件 名:LoginUserDAL '命名空间:LoginUserDAL '内 容: D层 '功 能: 实现接口sqlHlper '文件关系: '作 者:赵尽朝 '生成日期:2016.2.16 '版 本 号:V1.0.0.0 '修改日志: '版权说明: '*************************** Public Class LoginUserDAL : Implements IDAL.IuserinfoDAL '实现接口 '声明并实例化SQLHelper类 Public Function selectUser(UserInfo As LoginUserEntity) As DataTable Implements IuserinfoDAL.selectUser Dim sqlHelper As New sqlHelper.sqlHelper Dim sql As String Dim table As DataTable '中间变量,存储从数据库查到的信息 'Dim sqlParams As SqlParameter() = {New SqlParameter("@UserName", UserInfo.userName), New SqlParameter} Dim sqlParams As SqlParameter() = {New SqlParameter("@UserName", UserInfo.userName), New SqlParameter("@password", UserInfo.password)} '声明并实例化参数数组 sql = "select * from Users where userName=@UserName and password=@password" '下句为调用SqlHelper类中的GetDataTable()方法来执行查询,并获取返回值 table = sqlHelper.GetDataTable(sql, CommandType.Text, sqlParams) Return table End Function Private Function sqlHelper(sql As String, p2 As Object) As DataTable Throw New NotImplementedException End Function End Class</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports System.Data.SqlClient Imports LoginEntity '************************** '文 件 名:ScoreEntity '命名空间:ScoreEntity '内 容: 积分实体 '功 能: '文件关系: '作 者:赵尽朝 '生成日期:2016.2.16 '版 本 号:V1.0.0.0 '修改日志: '版权说明: '*************************** Public Class ScoreDAL : Implements IDAL.IScore Public Function UpdateScore(ByVal score As ScoreEntity) As Boolean Implements IDAL.IScore.UpdateScore Dim conn As SqlConnection = New SqlConnection("Server=DESKTOP-A8LHMG6\BIWORK2012;Database=机房重构;User ID=sa;Password=zjc") '设置连接 '定义cmd命令 Dim cmd As SqlCommand = conn.CreateCommand() cmd.CommandText = "INSERT INTO SCORES(UserName,Score) Values(@UserName,@Score)" cmd.Parameters.Add(New SqlParameter("@UserName", score.UserName)) cmd.Parameters.Add(New SqlParameter("@Score", score.Score)) conn.Open() '打开连接 cmd.ExecuteNonQuery() '执行增删改查操作 Return True '返回true End Function End Class </span>
工厂层
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports System.Configuration '添加对配置文件的引用 Imports System.Reflection '添加对反射的应用 Imports IDAL '************************** '文 件 名:LoginFactory '命名空间:LoginFactory '内 容: 抽象工厂 '功 能:配置文件信息读取 '文件关系: '作 者:赵尽朝 '生成日期:2016.2.16 '版 本 号:V1.0.0.0 '修改日志: '版权说明: '*************************** Public Class LoginFactory '读配置文件,D层的每个类都在配置文件里 对应一个KEY '吧Key变成变量, 'Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("strDB") Public Function CreateUserInfo() As IuserinfoDAL ''CType是一个内联函数,将前部分的表达式转换为后面的类型 Return CType(Assembly.Load("LoginDAL").CreateInstance("LoginDAL" & "." & "LoginUserDAL"), IuserinfoDAL) '返回IuserinfoDAL End Function Public Function CreateScoreInfo() As IDAL.IScore 'CType是一个内联函数,将前部分的表达式转换为后面的类型 Return CType(Assembly.Load("LoginDAL").CreateInstance("LoginDAL" & "." & "ScoreDAL"), LoginDAL.ScoreDAL) '返回IuserinfoDAL 'Ctype是一个内联函数,将前面的部分转化未后半部分 'LoginDAL为程序集名称 'Login.DAL为命名空间名称 'IUserInfoDal为要实例化的“类名” 'CreateUserInfo 创建实例 End Function End Class</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;">Public Interface IuserinfoDAL 'UserInfo为用户信息的实体,是由实体类实例化出来的 ,就是传实体 '此接口定义了一个方法,用来检查用户是佛存在。 Function selectUser(ByVal UserInfo As LoginUserEntity) As DataTable End Interface</span>
<pre name="code" class="vb"><span style="font-family:KaiTi_GB2312;font-size:18px;">Public Interface IScore '当前操作的 LoginEntity.ScoreEntity对象传递到参数score中,通过对该参数进行判断,显示数据的更改 Function UpdateScore(ByVal score As LoginEntity.ScoreEntity) As Boolean End Interface</span>
总结:
在以上的内容我们逐渐清晰了七层之间的数据传递,各层之间的引用理解的更清楚,设计模式的引用使得我们学习的更加透彻,以小故事的形式更利于记忆。为接下来的重构建立坚实基础,充分的理解为什么解耦、以及怎么更好的解耦。