在简单的三层登陆完成之后,我又在其中加入了设计模式,其中包括抽象工厂+反射和外观模式.关于设计模式,在学习三层之前我们已经系统的学习过,可是在这次往机房收费系统中加设计模式时,还是感觉无从下手,出现了学没有致用的尴尬情景.不过这也体现了我们提高班学习中项目驱动的优势.
接下来是我的一些现有思路,可能还不很准确,期待读者朋友的指点.
先说一下简单的三层登陆思想吧:
我们现阶段接触的三层就是最基本的三层--UI层,BLL层和DAL层.关于这三者之间的关系,在我前面博客中有所涉及,如果有兴趣,你可以参看:三层架构入门.
言归正传,理论知识我们知道了,在机房收费系统中,我们究竟是如何利用这三层来简化灵活我们的代码的呢?(由于.NET版本的登陆已经加入设计模式,所以简单三层用C#语言来展示.)
大家可以先看下主体代码:
UI层: 代码如下:
- <span style="font-size:18px;">private void btnOK_Click(object sender, EventArgs e)
- {
- UserInfo user = new UserInfo();
-
- string UserName = txtUserName.Text.Trim();
- string Password = txtPassword.Text.Trim();
- user.UserName=UserName ;
- user.Password = Password;
-
- LoginManager mgr = new LoginManager();
- UserInfo user2 = new UserInfo();
- user2 = mgr.UserLogin(user);
- MessageBox.Show("登录用户:" + user.UserName);
- }
- </span>
U层,就是我们窗体类,是用户唯一可以看到的部分.其中不涉及连接数据库,也不会包括业务逻辑.它主要负责接收用户输入指令并传给实体类,再有实体类传给B层,进行业务逻辑的判断.同时它也会根据B层产生的不同结果来及时反馈给用户.
BLL层: 代码如下:
- <span style="font-size:18px;">public class LoginManager
- {
- public UserInfo UserLogin(UserInfo user)
- {
-
- UserDAO uDAO = new UserDAO();
- user = uDAO.SelectUser(user );
-
- if (user != null)
- {
- ScoreDAO sDAO = new ScoreDAO();
- sDAO.UpdateScore(user, 10);
- return user;
- }
- else
- {
- throw new Exception("登录失败!");
- }
- }
- </span>
这一层是业务逻辑层,顾名思义,它主要负责系统中的绝大部分逻辑判断,一旦U层或者D层出现业务逻辑判断,我们就要考虑,它是不是应该放在B层.
DAl层: 代码如下:
- <span style="font-size:18px;">namespace Login.DAL
- {
- public class UserDAO
- {
-
-
-
-
-
- public UserInfo SelectUser(UserInfo user)
- {
- using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))
- {
- SqlCommand cmd = conn.CreateCommand();
- cmd.CommandText = @"SELECT ID, UserName,Password,Email from Users where UserName=@UserName and Password=@Password";
- cmd.CommandType = CommandType.Text;
-
- cmd.Parameters.Add(new SqlParameter ("@UserName",user.UserName ));
- cmd.Parameters.Add(new SqlParameter ("@Password",user.Password ));
- conn.Open();
-
- SqlDataReader reader = cmd.ExecuteReader();
- user=null;
- while (reader .Read ())
- {
- if (user == null)
- {
- user = new UserInfo();
- }
- user.ID = reader.GetInt32(0);
- user.UserName = reader.GetString(1);
- user.Password = reader.GetString(2);
- if (!reader.IsDBNull(3))
- {
- user.Email = reader.GetString(3);
- }
- }
- return user;
- }
- }
- }
- }
- </span>
从以上的代码就可以看出,D层主要是连接数据库,从数据库中读取信息,然后再以实体的形式传给B层,B层传给U层,最后表现在用户面前.
上述是没有添加设计模式的简单三层登陆,下面就要谈一谈为什么要加设计模式,以及如何添加设计模式了.
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结.使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。也许这样说读者还是不大明白,下面的代码展示或许可以给您一些启示.
首先说一下抽象工厂+反射,在机房登录中的应用(只展示主体代码,方便理解).
Abstract Factory: 抽象工厂接口,它里面包含所有产品创建的抽象方法.工厂类被BLL层调用,并调用IDAL接口,使用配置文件读取数据库字符串.通过反射技术,解除简单工厂更换数据库时的分支判断带来的耦合.
代码如下:
- <span style="font-size:18px;">Imports System.Configuration
- Imports System.Reflection
- Imports IDAL
-
- Public Class SqlFactory
- Private Shared ReadOnly AssemblyName As String = "DAL"
-
- Private Shared DB As String = ConfigurationManager.AppSettings("strDB")
-
- #Region "获取用户信息"
- Public Shared Function CreatGetUserInfo() As IDAL.IGetUserInfo
- Dim UserInfo As IGetUserInfo
- Dim ClassName As String
-
- ClassName = AssemblyName + "." + DB + "D_GetUserInfo"
- UserInfo = CType(Assembly.Load(AssemblyName).CreateInstance(ClassName), IDAL.IGetUserInfo)
- Return UserInfo
- End Function
- #End Region
- </span>
IDAL接口: 被B层和D层调用,使得B层和D层的耦合度极大降低.
- <span style="font-size:18px;">Imports Entity
-
- Public Interface IGetUserInfo
- Function GetUserInfo(ByVal e_Users As Entity.E_UserInfoEntity) As DataTable
- End Interface
- </span>
BLL层: 定义接口类,并使用工厂类SqlFactory方法反射实例化相应的DAl类.这时候B层和D层已经完全不再耦合,B层或者D层的任何变动,都不会影响另一层.(这就是我们使用抽象工厂加反射的最大用处了.)
- <span style="font-size:18px;">Imports Entity
- Imports IDAL
- Imports DBFactory.SqlFactory
- Imports DAL
-
- Public Class B_UserInfo
-
- Public SqlFactory As New DBFactory.SqlFactory
- #Region "验证用户密码"
- Public Function VerifyPassword(ByVal EUserInfo As E_UserInfoEntity) As Boolean
-
-
- Dim IGetPWD As IDAL.IGetUserInfo
- IGetPWD = DBFactory.SqlFactory.CreatGetUserInfo
- Dim dtUserInfo As DataTable
- dtUserInfo = IGetPWD.GetUserInfo(EUserInfo)
-
- If dtUserInfo.Rows.Count = 0 Then
- Throw New Exception("该用户还未注册!")
- Return False
- End If
-
-
- If EUserInfo.Passwrod = Trim(dtUserInfo.Rows(0).Item(1)) Then
- Return True
- Else
- Return False
- End If
- End Function
- #End Region
- End Class
- </span>
抽象工厂和反射解耦和B层和D层.接下来的外观模式就要解耦U层和B层了.
Facade类: 在简单的三层中,界面层的登陆需要根据B层返回的值再进行判断,这样B层和U层的耦合度是比较高的.而加入外观模式后,上面提到的对B层返回值进行判断就可以移到外观类中.这样就充分实现了B层和U层的分离.
- <span style="font-size:18px;">Imports Entity
- Imports BLL
-
- Public Class Login
- Private bUserInfo As New B_UserInfo
- Dim blnFlag As Boolean = False
-
-
-
-
-
-
- Public Function IsPassword(ByVal eUserInfo As E_UserInfoEntity) As Boolean
- Try
- blnFlag = bUserInfo.VerifyPassword(eUserInfo)
- Catch ex As Exception
- MsgBox(ex.Message, vbOKOnly, "提示信息")
- End Try
-
- If blnFlag = True Then
- Return True
- Else
- MsgBox("密码错误,请重新输入!")
- Return False
- End If
- End Function
- End Class
- </span>
UI层: 外观层在对B层返回值进行判断之后,返回信息给UI层.这样U层和B层就实现了分离,两者中任何一层发生变化都不用修改另一层的代码.
- <span style="font-size:18px;">Imports Entity
- Imports BLL
- Imports Facade.Login
-
-
- Public Class frmLogin
- Public bUserInfo As New B_UserInfo
- Public faUserInfo As New Facade.Login
-
- Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
- Dim aUserInfo As New Entity.E_UserInfoEntity
- Dim blnFlag As Boolean = False
-
- aUserInfo.UserID = Trim(txtUserName.Text)
- aUserInfo.Passwrod = Trim(txtPassword.Text)
-
-
- Try
- blnFlag = faUserInfo.IsPassword(aUserInfo)
- Catch ex As Exception
- MsgBox(ex.Message, vbOKOnly, "提示信息")
- End Try
-
- If blnFlag = True Then
- frmMain.Show()
- End If
- End Sub
- End Class
- </span>
上述是我现阶段对三层和部分设计模式的理解,错误之处希望读者朋友多多指教!