首页 > 代码库 > 三层架构入门实例

三层架构入门实例


三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。区分层次的目的即为了“高内聚,低耦合”的思想。

首先我们先用一组生活中的图片来说明三层的重要性。(摘自网络)  


生活中的实例 

饭店有三个分工,服务员,厨师和采购员

 

分三层,松耦合,更方便应对变化。

      

实际这种思想也适用于我们的三层架构。


UI只负责显示和采集用户操作,不包含任何的业务相关的逻辑处理。

BLL 负责处理业务逻辑,通过UI传来的操作指令,决定执行业务逻辑,在需要访问数据源的时候直接交给DAL处理。处理完成后,返回必要的数据给UI.

DAL之提供基本的数据访问,不包含任何也不相关的逻辑处理。


二 系统登陆流程 


以程序执行的顺序跑一遍,是下图这样的流程。可以看到,每层的分工明确。各司其职。



    此处演示的三层架构实例中,层层之间都要通过用户名和密码两个变量来传递。这是一种方法,但是实际中也有可能,我们需要更多的信息,如学号,年龄,性别,地址等。为了更加方便的传输数据,还可以通过实体来传输。将这些信息做成某一实体的属性,层与层之间穿实体,每层用时只需调用实体的属性即可。下文的模型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信息


以上是三层架构的基本实例,感觉断点调试的收获是最大的。先写到这里,学习继续~