天天看點

三層架構入門執行個體

三層架構(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 [email protected] AND [email protected]";
                 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層等。我感覺它讓我的思路更清晰了。 

繼續閱讀