很早之前,就聽說過三層結構了。當時只知道 三層結構 是把 系統的 界面 跟 數據庫操作等不相關的程序分別開來。原來這麼簡單的實現,確實傳說中的 三層結構啊。
首先,先來看一下是哪三層。表示層(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();
}
}
}
}
接下來,看一下執行結果:
執行成功的情況:

輸入錯誤信息:

雖然這是一個很小的實例,但是用來學習三層卻足夠了。有寫的不好的地方可以理解。
總結:對於使用三層架構的程序來說,哪層出錯改哪裡。極大程度的降低了系統的耦合性。當然,具有層次的程序,維護起來必然要方便許多。