#前言
三层代码就在我的眼前,可是我却不能理解,你能想象我当时的心情嘛?
但是功夫不负有心人(我也终于可以说这句话了哈哈哈)
经过翻阅无数篇博客,还有问各位计算机大神,当然还有我的独立思考,终于把这个小三层给弄明白了!
开心耶!
#什么是三层?
在学习三层的时候,先问自己一个为什么?在以前我们敲学生系统,机房收费系统都有登陆的窗体,都可以好好的运行,但是为什么会出现这个叫“三层”的东西呢?什么是三层呢?
三层:包括显示层(UI),业务逻辑层(BLL),数据访问层(DAL)。是将代码按照类别归到这三个层中,目的是为了解耦和,防止出现很多代码堆积在一起的混沌状态,也便于代码的复用和可扩展性同时也减少了维护的费用。
#三层的理解?
对于这三个层具体是做什么?有什么联系,可不可以用生活中的例子去理解呢?
请看我的这篇博客:
这篇博客利用生活中的实例去解释了三层的关系。
https://blog.csdn.net/hdy14/article/details/78445551
同时我们也可以用一个图很好的去理解三层。
#三层登录各层间调用关系
三层登录和VB中的登录窗体比较,只是把代码分类存放,目的是解耦,便于复用和维护,所以既然三层已经分隔开,如果没有相互调用和返回值,怎么进行彼此间的联系呢?
UI层调用BLL:
Login.BLL.LoginService mgr = new Login.BLL.LoginService();//实例化BLL层,实例出一个BLL的类mgr
Login.Model.Userinfo user = mgr.Login(userName, password);//调用BLL层的类和方法mgr.Login,并得到一个返回值
BLL层调用DAL:
Login.DAL.UserDAO uDao = new Login.DAL.UserDAO();//实例化D层,实例出一个uDao类
Login.Model.Userinfo user = uDao.SelectUser(userName, password);//调用D层类和方法uDao.SelectUser,并得到一个返回值
#具体三层代码实现
这个是一个结合积分的登录实现,当登录成功的时候,会给用于加10分,所以在D层有一个加分的类。
实体层是一个放各个实体的类,便于各个层去使用。
##UI
using System;
using System.Windows.Forms;
namespace LoginUI
{
public partial class Form1 : Form //partial表示部分类,前边的两个词都是修饰类form1 的 而 冒号:表示继承, form是父类
{
public Form1()
{
InitializeComponent();//这是一个方法
}
private void btnLogin_Click(object sender, EventArgs e)//显示层不能和数据打交道,应该放到业务逻辑层
{ //此为按钮的单击事件
//IDbConnection conn = new SqlConnection("C...");
//IDbCommand cmd = conn.CreateCommand();
//cmd.CommandText = "Select UserName Form USER WHERE ....";
//cmd.ExecuteReader();
string userName = txtUserName.Text.Trim(); //定义两个局部变量
string password = txtPassword.Text;
Login.BLL.LoginService mgr = new Login.BLL.LoginService();//实例化BLL层,实例出一个BLL的类mgr
Login.Model.Userinfo user = mgr.Login(userName, password);//调用BLL层的类和方法mgr.Login,并返回一个值
MessageBox.Show("登录用户" + user.UserName);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
##BLL
using System;
using Login.DAL;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.BLL //业务逻辑层 ,对用户名和密码进行判断,如果用户名密码正确,就添加积分,否则就错误
{
public class LoginService
{
public Login.Model.Userinfo Login (string userName, string password)//对用户名和密码进行设置,Login是个方法
{
//throw new NotImplementedException();
Login.DAL.UserDAO uDao = new Login.DAL.UserDAO();//实例化D层,实例出一个uDao类
Login.Model.Userinfo user = uDao.SelectUser(userName, password);//调用D层类和方法uDao.SelectUser,并返回一个值
if (user != null) //Login successful。 //判断用户名和密码是否为空?
{
Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO();//设置一个变量,方便计算积分 绿色的是一个方法
sDao.UpdateScore(userName, 10);//userName可以看成是一个主键
return user;//刚才将值给了user ,现在的操作是将这个有值的变量返回去
}
else
{
throw new Exception("登录失败");
};
}
}
}
##DAL
DbUtil
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
namespace Login.DAL
{
class DbUtil //DbUtil是一个连接数据库的类
{
public static string ConnString = @"Server=DESKTOP-5O0DBNT\MYSERVER; Database= Login ; User ID = sa; Password = 123456 "; //@是避免转义字符的意思。
//机器名+数据库名+用户名和密码
}
}
ScoreDAO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using Login.DAL;
namespace Login.DAL
{
public class ScoreDAO//积分,每一个登陆都有积分
{
public void UpdateScore(string userName , int value)
{
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = @"INSERT INTO Scores (UserName,Score) Values(@UserName ,@Score)";//两个参数
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
cmd.Parameters.Add(new SqlParameter("@Score", value));//数值型
conn.Open();
// cmd.ExecuteNonQuery();
}
}
}
}
UserDAO
using System.Data;
using System.Data.SqlClient;
using Login.DAL;
namespace Login.DAL
{
public class UserDAO
{
public Login.Model.Userinfo SelectUser(string userName, string password)
{
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", userName));
cmd.Parameters.Add(new SqlParameter("@Password", password));
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
Login.Model.Userinfo user = null;//初始化user
while (reader.Read())
{
if(user ==null )
{
user = new Login.Model.Userinfo();
}
user.ID = reader.GetInt32(0);
user.UserName = reader.GetString(1);
user.UserName = reader.GetString(2);
if (!reader.IsDBNull(3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
}
Model(实体层)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.Model
{
public class Userinfo //定义一个userinfo 的类
{
public int ID { get; set; }
public string UserName { get; set;}
public string Password { get; set;}
public string Email { get; set; }
}
}
#后记
三层很好的体现了面向对象的特征,封装,继承,多态。
我知道我理解也不是特别的深入,我们还需要慢慢去品味,代码的逻辑,代码的魅力!
多去问为什么,有一个不将就的态度,我们就会变的很厉害,也可以帮助更多的人,创作出用户最满意的产品。