本文共 4496 字,大约阅读时间需要 14 分钟。
说到三层,先来说一说两层结构。两层结构将界面展示、业务逻辑、数据访问等都写到一起,如果用户需求变化,就需要对整个项目进行大量修改,系统的维护和升级极其不利;而且界面层直接访问数据库,还会有安全隐患。结构如下图所示: 所以基于两层结构的局限性,三层结构就出现了。三层结构符合“高内聚、低耦合”的特点,每个层职责明确。利用分层,降低了层间依赖,使系统的耦合更加松散,从而使系统更加容易维护和复用。 比如:如果需求有变化,只需要更改相应的业务逻辑层;或者要改变数据库的时候,只需要将原来的数据访问层替换掉或者增加新的就可以了,而不需要牵扯到整个项目。 三层架构虽好,但是也不是每个项目都必须采用这种结构,三层结构用于比较复杂的大型系统,如果系统比较小,则没必要将问题复杂化。
三层由显示层(UI)、业务逻辑层(BLL)、数据访问层(DAL)组成。 1.显示层(UI) 职责:①向用户展示特定的业务数据 ②采集用户的信息和操作 原则:用户至上,兼顾简洁
2.业务逻辑层(BLL) 职责:① 从UI中获取用户指令和数据,执行业务逻辑 ②从UI中获取用户指令和数据,通过DAL写入数据源 ③从DAL中获取数据,以供 UI 显示用 机制:① UI –> BLL –> UI ② UI –> BLL –> DAL –> BLL –> UI
3.数据访问层(DAL) 作用:跟数据源打交道 职责:①执行对数据的操作(增删改查)
4.数据对象层 数据对象层包含了项目需要使用的数据对象,用数据对象来传递数据,它避免了各个层的交叉引用。 一般一个表对应一个数据对象。
上图已经展示了它们三者之间的引用关系。UI层–> BLL层 –> DAL层,而它们都引用数据对象层。
下面以一个登录的小例子,展示一下三层是如何具体使用的。 UI层:
public partial class Form1 : Form{ public Form1() { InitializeComponent(); } private void btnLogin_Click(object sender, EventArgs e) { //获取输入的用户名和密码 string userName = txtUserName.Text.Trim(); string userPassword = txtPassword.Text; Login.BLL.LoginManager mgr = new Login.BLL.LoginManager(); //调用B层的登录方法,从B层返回user的信息 UserInfo user = mgr.Login(userName, userPassword); MessageBox.Show("登录用户:" + user.UserName); }}
BLL层:
public class LoginManager{ public UserInfo Login(string userName,string password) { //实例化UserDao UserDAO uDao = new UserDAO(); //调用UserDao的查询用户方法 UserInfo user = uDao.SelectUser(userName, password); //如果用户存在,就调用ScoreDao的更新积分方法,给用户加10积分;否则就抛出异常 if (user != null) { ScoreDAO sDao = new ScoreDAO(); //调用ScoreDao的更新积分方法 sDao.UpdateScore(userName, 10); return user; } else { throw new Exception("登录失败。"); } }}
DAL层:
public class UserDAO{ ////// 查询用户是否存在并返回用户信息 /// /// 用户名 /// 密码 ///public UserInfo SelectUser(string userName,string password) { using (SqlConnection conn = new SqlConnection(DbUtil.ConnString)) { SqlCommand cmd = conn.CreateCommand(); //获取执行的SQL语句 或表名 或存储过程名 cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password"; //指示执行的是存储过程还是sql语句,默认执行语句 cmd.CommandType = CommandType.Text; cmd.Parameters.Add(new SqlParameter("@UserName", userName)); cmd.Parameters.Add(new SqlParameter("@Password", password)); conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); UserInfo 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; } }}public class ScoreDAO{ /// /// 更新用户积分 /// /// 用户名 /// 要增长的积分 public void UpdateScore(string userName,int value) { using (SqlConnection conn = new SqlConnection(DbUtil.ConnString)) { SqlCommand cmd = conn.CreateCommand(); //查询Scores表中是否已有用户信息 cmd.CommandText = @"SELECT * FROM Scores WHERE UserName =@UserName"; cmd.CommandType = System.Data.CommandType.Text; cmd.Parameters.Add(new SqlParameter("@UserName", userName)); cmd.Parameters.Add(new SqlParameter("@Score", value)); conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); //如果Scores表中用户积分已存在就在原来的基础上加10份;否则就插入新的用户积分数据 if (reader.Read()) { //在用户原有积分基础上加10分 cmd.CommandText = @"UPDATE Scores SET Score+=10 WHERE UserName = @UserName"; //关闭reader reader.Close(); //执行SQL语句 cmd.ExecuteNonQuery(); } else { reader.Close(); //插入新的用户积分数据 cmd.CommandText = @"INSERT INTO SCORES(UserName,Score) Values(@UserName,@Score)"; cmd.ExecuteNonQuery(); } } }}