在简单的三层登陆完成之后,我又在其中加入了设计模式,其中包括抽象工厂+反射和外观模式.关于设计模式,在学习三层之前我们已经系统的学习过,可是在这次往机房收费系统中加设计模式时,还是感觉无从下手,出现了学没有致用的尴尬情景.不过这也体现了我们提高班学习中项目驱动的优势.
接下来是我的一些现有思路,可能还不很准确,期待读者朋友的指点.
先说一下简单的三层登陆思想吧:
我们现阶段接触的三层就是最基本的三层--UI层,BLL层和DAL层.关于这三者之间的关系,在我前面博客中有所涉及,如果有兴趣,你可以参看:三层架构入门.
言归正传,理论知识我们知道了,在机房收费系统中,我们究竟是如何利用这三层来简化灵活我们的代码的呢?(由于.NET版本的登陆已经加入设计模式,所以简单三层用C#语言来展示.)
大家可以先看下主体代码:
UI层: 代码如下:
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;
//实例化BLL层,并调用BLL层方法
LoginManager mgr = new LoginManager();
UserInfo user2 = new UserInfo();
user2 = mgr.UserLogin(user);
MessageBox.Show("登录用户:" + user.UserName);
}
U层,就是我们窗体类,是用户唯一可以看到的部分.其中不涉及连接数据库,也不会包括业务逻辑.它主要负责接收用户输入指令并传给实体类,再有实体类传给B层,进行业务逻辑的判断.同时它也会根据B层产生的不同结果来及时反馈给用户.
BLL层: 代码如下:
public class LoginManager
{
public UserInfo UserLogin(UserInfo user)
{
//实例化DAL层,并调用DAL层方法
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("登录失败!");
}
}
这一层是业务逻辑层,顾名思义,它主要负责系统中的绝大部分逻辑判断,一旦U层或者D层出现业务逻辑判断,我们就要考虑,它是不是应该放在B层.
DAl层: 代码如下:
namespace Login.DAL
{
public class UserDAO
{
/// <summary>
/// 连接数据库,获取用户信息
/// </summary>
/// <param name="user">用户信息实体</param>
/// <returns>用户信息</returns>
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 ())//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;
}
}
}
}
从以上的代码就可以看出,D层主要是连接数据库,从数据库中读取信息,然后再以实体的形式传给B层,B层传给U层,最后表现在用户面前.
上述是没有添加设计模式的简单三层登陆,下面就要谈一谈为什么要加设计模式,以及如何添加设计模式了.
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结.使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。也许这样说读者还是不大明白,下面的代码展示或许可以给您一些启示.
首先说一下抽象工厂+反射,在机房登录中的应用(只展示主体代码,方便理解).
Abstract Factory: 抽象工厂接口,它里面包含所有产品创建的抽象方法.工厂类被BLL层调用,并调用IDAL接口,使用配置文件读取数据库字符串.通过反射技术,解除简单工厂更换数据库时的分支判断带来的耦合.
代码如下:
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
IDAL接口: 被B层和D层调用,使得B层和D层的耦合度极大降低.
Imports Entity
Public Interface IGetUserInfo
Function GetUserInfo(ByVal e_Users As Entity.E_UserInfoEntity) As DataTable
End Interface
BLL层: 定义接口类,并使用工厂类SqlFactory方法反射实例化相应的DAl类.这时候B层和D层已经完全不再耦合,B层或者D层的任何变动,都不会影响另一层.(这就是我们使用抽象工厂加反射的最大用处了.)
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
抽象工厂和反射解耦和B层和D层.接下来的外观模式就要解耦U层和B层了.
Facade类: 在简单的三层中,界面层的登陆需要根据B层返回的值再进行判断,这样B层和U层的耦合度是比较高的.而加入外观模式后,上面提到的对B层返回值进行判断就可以移到外观类中.这样就充分实现了B层和U层的分离.
Imports Entity
Imports BLL
Public Class Login
Private bUserInfo As New B_UserInfo
Dim blnFlag As Boolean = False
''' <summary>
''' 对B层的返回值进行逻辑判断
''' </summary>
''' <param name="eUserInfo">用户信息实体</param>
''' <returns>用户信息正确返回True,错误返回False</returns>
''' <remarks></remarks>
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
UI层: 外观层在对B层返回值进行判断之后,返回信息给UI层.这样U层和B层就实现了分离,两者中任何一层发生变化都不用修改另一层的代码.
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)
'调用外观类的IsPassword方法进行逻辑判断
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
上述是我现阶段对三层和部分设计模式的理解,错误之处希望读者朋友多多指教!