很早之前,就聽說過三層結構了。當時只知道 三層結構 是把 系統的 界面 跟 數據庫操作等不相關的程序分別開來。原來這麼簡單的實現,確實傳說中的 三層結構啊。
首先,先來看一下是哪三層。表示層(UI,User Interface),業務邏輯層(BLL BusinessLogicLayer),數據訪問層(DAL Data Access Layer)。三層的劃分是物理上的劃分。
表示層(UI),這個最容易理解,就是用戶看到的主界面。
數據訪問層(DAL),也不難理解,主要是負責數據的增刪改查。
業務邏輯層(BLL),算是表示層和數據訪問層的橋梁吧。裡面主要存放一些業務流程。也就是邏輯。主要作用就是從DAL中獲取數據,然後顯示到UI上。
舉一個例子,三層結構可以用飯店的實例來理解。
UI指的是服務員,BLL是廚師,DAL是采購員。
在顧客的眼裡,只能看到服務員為他們服務。並不知道後台廚師和采購員是如何做的。對於上述三種不同的角色來說,無論哪個環節出了問題,只需要更換一個員工就可以照常營業的。
三層架構的優勢,還是職責分離,降低耦合。
接下來,看一個使用三層結構的登陸實例。首先,需要聲明一下。這個實例中有很多bug需要優化。不過對於展示三層的主要思想足夠了。僅僅是一個實例而已。
數據庫表:
這是數據模塊圖:
細心的讀者肯定會發現,除了UI,BLL,DAL這三個之外還有一個Moudel存在,這個Moudel不屬於任何一層,只是為了更好地鏈接三層而存在的。這個類只存儲,與以上三類共同使用的東西。起一個協調的作用。Moudel類,也就是實體類。
下面是這幾個層次的關系。
接下來需要看一下,他們分別是如何實現各自的分工的。
Entity類:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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; } } }
U層:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace LoginUI { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void label1_Click(object sender, EventArgs e) { } private void btnLogin_Click(object sender, EventArgs e) { try { 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); //使用用戶界面數據 進行查找 //如果沒有問題,則登陸成功 MessageBox.Show("登陸用戶:" + user.UserName); } catch (Exception ex) //如果登陸有異常 則登陸失敗 { MessageBox.Show(ex.Message); } } } }
B層:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Login.BLL //業務邏輯層 { public class LoginManager { public Login.Model.UserInfo UserLogin(string userName, string Password) { ///throw new NotImplementedException(); Login.DAL.UserDAO uDAO = new Login.DAL.UserDAO(); //創建一個user Login.Model.UserInfo user= uDAO.SelectUser(userName, Password); //通過ui中填寫的內容 返回來相應的數據 if (user!= null) //如果數據庫中沒有數據,即為首次登陸了。增加10積分 { Login.DAL.ScoreDAO sDAO = new Login.DAL.ScoreDAO(); sDAO.UpdateScore(userName, 10); return user; } else //如果數據庫中沒有該用戶名,則登陸失敗 { throw new Exception("登陸失敗"); } } } }
D層:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Login.DAL //數據訪問層 { class DbUtil //用於保存 鏈接服務器的sql語句 { public static string ConnString = @"Server=zc-pc;Database=Login;User ID=sa; Password=123456"; } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.Data.SqlClient; namespace Login.DAL { public class UserDAO { public Login.Model.UserInfo SelectUser(string userName, string Password) //根據 ui 選擇返回一個user { 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; //用於保存讀取的數據 while (reader.Read()) //開始讀取數據 { 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)) //不要求一定要有email,也可以返回 { user.Email=reader.GetString(3); } } return user; } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.SqlClient; namespace Login.DAL { public class ScoreDAO //首次登陸,增加10積分 { 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)"; //修改Score表數據 cmd.Parameters.Add(new SqlParameter("@userName", userName)); cmd.Parameters.Add(new SqlParameter("@Score", value)); conn.Open(); cmd.ExecuteNonQuery(); } } } }
接下來,看一下執行結果:
執行成功的情況:
輸入錯誤信息:
雖然這是一個很小的實例,但是用來學習三層卻足夠了。有寫的不好的地方可以理解。
總結:對於使用三層架構的程序來說,哪層出錯改哪裡。極大程度的降低了系統的耦合性。當然,具有層次的程序,維護起來必然要方便許多。