三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。区分层次的目的即为了“高内聚,低耦合”的思想。
首先我们先用一组生活中的图片来说明三层的重要性。(摘自网络)
饭店有三个分工,服务员,厨师和采购员
分三层,松耦合,更方便应对变化。
实际这种思想也适用于我们的三层架构。
UI只负责显示和采集用户操作,不包含任何的业务相关的逻辑处理。
BLL 负责处理业务逻辑,通过UI传来的操作指令,决定执行业务逻辑,在需要访问数据源的时候直接交给DAL处理。处理完成后,返回必要的数据给UI.
以程序执行的顺序跑一遍,是下图这样的流程。可以看到,每层的分工明确。各司其职。
此处演示的三层架构实例中,层层之间都要通过用户名和密码两个变量来传递。这是一种方法,但是实际中也有可能,我们需要更多的信息,如学号,年龄,性别,地址等。为了更加方便的传输数据,还可以通过实体来传输。将这些信息做成某一实体的属性,层与层之间穿实体,每层用时只需调用实体的属性即可。下文的模型Model就是依据这样的思路建立的。.
界面如图。
首先先在数据库中 新建Login数据库,并设计Scores 和users两表。
ID均为自增长。
MODEL1
生成一个用户实体,便于传输数据。因此,其他各层之间都要添加对它的引用。
namespace Login.Model//其他程序集引用它,但它不会引用其他程序集 { public class UserInfo { public int ID { get; set; } public string Username { get; set; } public string Password { get; set; } public string Email { get; set; } } }
UI层,收集数据显示数据,需要添加对BLL和Model的引用。将数据信息赋给Model的UserInfo。我们看代码便可知并没有任何的业务和SQL等的操作。涉及到业务逻辑交给BLL。
namespace LoginUI { public partial class Form1 : Form { private void Form1_Load(object sender, EventArgs e) {} public Form1() { InitializeComponent(); } private void btnLogin_Click(object sender, EventArgs e) { string userName = txtUserName.Text.Trim();//收集数据 string password=txtPassword .Text; Login.BLL .LoginManager mgr= new Login.BLL.LoginManager (); Login.Model.UserInfo user = mgr.UserLogin(userName, password);//具体业务逻辑交给 BLL层 LoginManager MessageBox.Show("登陆用户:" + user.Username);//界面负责显示 } } }
BLL介于 UI和DAL之间,需要添加对DAL和Model的引用。它做的业务逻辑是判断用户名密码是否成立并增加积分。 但是,判断过程需要用数据源,这一部分工作交给DAL,等DAL返回数据之后,再继续进行积分的业务操作。
namespace Login.BLL { public class LoginManager { public Login.Model.UserInfo UserLogin(string userName, string password) { //业务逻辑层要判断用户密码是否成立 所以它需要数据库中的信息 Login.DAL.UserDAO uDao = new Login.DAL.UserDAO(); Login.Model .UserInfo user=uDao.SelectUser(userName, password);//把D层的查询到的信息再赋给Model中的UserInfo //由于用户密码这些信息需要访问数据库 所以交给DAL处理。从这里转移到DAL。待DAL完成之后,返回从数据库中查询回来 程序转移到这里。 //业务逻辑层接着判断如果存在配套的用户名和用户密码 则增加积分。 if (user != null)//user不为空,说明在数据库中查到了符合条件的信息。login successfully { Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO(); sDao.UpdateScore(userName,10);//由于在数据库中增加积分 涉及到对数据的操作,程序从这里跳转到DAL 的UserDAO。然后将10传进积分 return user;//将BAL层中的user 传回UI } else { throw new Exception("登陆失败。"); } } } }
DAL层,需要添加对Model的引用。因为查询用户和添加积分都要对数据库操作。因此在该层做了两个类。UserDAO,将查询到的信息更新到UserInfo信息中。ScoreDAO 直接在数据库中添加积分信息。
namespace Login.DAL {// 只提供基本的数据访问,不包含任何业务相关的逻辑处理 public class UserDAO { public Login.Model .UserInfo SelectUser(string userName, string password) //手动更改的public { //查看数据库是否有配套的用户名和密码 using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))//使用using ,connection就可自动关闭 { 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; while (reader.Read())//reader是一条一条读数据的,读之前它会确认是还有数据。read()会返回一个布尔值,有则为true,没有就是false。 { if (user == null) { user = new Login.Model.UserInfo(); } user.ID = reader.GetInt32(0); user.Username = reader.GetString(1); user.Password = reader.GetString(2); if (!reader.IsDBNull(3))//因为空值不能调用GetString方法 故需要做一个判断 { user.Email = reader.GetString(3); } } return user; } } } }
ScoreDAO
namespace Login.DAL { public class ScoreDAO { public void UpdateScore(string userName, int value) {//给该用户在数据库中添加积分 using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))//using 可以自动关闭连接 { 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(); } } } }
整个过程清楚之后,我们再来 看一下Model的UserInfo类是如何在各层之间活蹦乱跳地传输的。
1,UI层,将输入的用户名和密码赋给变量。将变量作为参数传到BLL层的UserLogin(UserInfo类)中。
2,BLL层,将UserLogin得到的参数传给DAL层SelectUser(UserInfo类)中。
3,DAL 通过得到的参数查询数据库。再将查询到的信息返回给User,通过传输到BLL层。
4,BLL层将积分10和LoginUser中的userNameUser传到DAL层的UpdateScore中。
5,DAL利用UpdateScore的参数更新数据库,返回到BLL层。
6,BLL层将User返回到UI层
7,UI层显示User信息
以上是三层架构的基本实例,感觉断点调试的收获是最大的。不断调试的过程就会慢慢的熟悉它的流程和工作过程。它的思想和设计模式是一样一样的。都在寻求更优更灵活的解决方案。有了这种层次感 在思考的时候,也会想哪里是U层,怎么样用B层等。我感觉它让我的思路更清晰了。