前言
當看到一個陌生的名詞時你會怎麼想?what?way?how? 現在就按照這個思維框架走進“三層架構”。
什麼是三層架構?
在軟件體系架構設計中,分層式結構是最常見,也是最重要的一種結構。微軟推薦的分層式結構一般分爲三層,從下至上分別爲:數據訪問層、業務邏輯層(又或稱爲領域層)、表示層。
1、表示層(UI):通俗講就是展現給用戶的界面,即用戶在使用一個系統的時候他的所見所得。
2、業務邏輯層(BLL):針對具體問題的操作,也可以說是對數據層的操作,對數據業務邏輯處理。
3、數據訪問層(DAL):該層所做事務直接操作數據庫,針對數據的增添、刪除、修改、查找等。
微軟的DNA架構定義了三個層:表示層(presentation),業務邏輯層(business),和數據訪問層(data access)。具體又分爲:界面外觀層、界面規則層、業務接口層、業務邏輯層、實體層、數據訪問層、數據存儲層共七層,其具體的調用如下圖所示:
爲什麼要用三層架構?
對於一個簡單的應用程序來說,代碼量不是很多的情況下,一層結構或二層結構開發完全夠用,沒有必要將其複雜化,如果對一個複雜的大型系統,設計爲一層結構或二層結構開發,那麼這樣的設計存在很嚴重缺陷。
分層開發其實是爲大型系統服務的。在開發過程中,初級程序人員出現相似的功能經常複製代碼,那麼同樣的代碼寫那麼多次,不但使程序變得冗長,更不利於維護,一個小小的修改或許會涉及很多頁面,經常導致異常的產生使程序不能正常運行。最主要的面向對象的思想沒有得到絲毫的體現,打着面向對象的幌子卻依然走着面向過程的道路。
意識到這樣的問題,初級程序人員開始將程序中一些公用的處理程序寫成公共方法,封裝在類中,供其它程序調用。例如寫一個數據操作類,對數據操作進行合理封裝,在數據庫操作過程中,只要類中的相應方法(數據添加、修改、查詢等)可以完成特定的數據操作,這就是數據訪問層,不用每次操作數據庫時都寫那些重複性 的數據庫操作代碼。在新的應用開發中,數據訪問層可以直接拿來用。面向對象的三大特性之一的封裝性在這裏得到了很好的體現。現在找到了面向對象的感覺,代碼量較以前有了很大的減少,而且修改的時候也比較方便,也實現了代碼的重用性。
優缺點:
(一)優點
1、開發人員可以只關注整個結構中的其中某一層;
2、可以很容易的用新的實現來替換原有層次的實現;
3、可以降低層與層之間的依賴;
4、有利於標準化;
5、利於各層邏輯的複用。
(二)缺點
1、降低了系統的性能。這是不言而喻的。如果不採用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。
2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,爲保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼。
3、增加了開發成本。
怎麼用三層架構?
不是所有的系統都需要使用三層架構,在一開始學習這塊知識的時候有可能會存在誤區。對於簡單的問題我們沒有必要把它複雜化,甚至有可能會畫蛇添足、多此一舉。
不需要使用的情況:
1業務邏輯簡單。
2、沒有真正的數據存儲層。
需要使用的情況:
既有數據訪問層DAL又有業務邏輯層BLL,也就是說當業務複雜到一定程度後,數據需要單獨的存儲到相對獨立的介質中時,需要把數據訪問脫離開業務單獨存在,把業務脫離開UI單獨存在,UI達到業務只需要呼叫業務訪問層即可實現跟用戶訪問的交互。這種情況下我們才使用三層結構。
實例演練:
現在有一個積分系統,學生每登錄一次可獲得10積分獎勵。代碼入下:
UI層:
private void btnLogin_Click(object sender, EventArgs e)
{
string userName=txtUsername.Text.Trim();
string password=txtPassword.Text;
LoginBll.LoginManager mgr = new LoginBll.LoginManager(); //實例化一個業務層的LoginManager,用於邏輯判斷
LoginModel.UserInfo user= mgr.UserLogin(userName, password); //實例化一個業務層的Model,用於給userlogin賦值name,password
MessageBox.Show("登錄用戶: " + user.UserName); //顯示登錄信息
}
BLL層:
namespace LoginBll
{
//管理登錄類,用於判斷用戶是否登陸成功
public class LoginManager
{
//UI層傳遞的是UserInfo方法,數據是Username,password
public LoginModel.UserInfo UserLogin(string userName, string password) //UserLogin方法,判斷登錄信息是否正確
{
LoginDAL.UserDAO uDao = new LoginDAL.UserDAO(); //實例化一個數據層登錄
LoginModel.UserInfo user = uDao.SelectUser(userName, password); //實例化一個Model,用於給數據層的SelectUser賦值
if (user!=null)
{
LoginDAL.SocreDAO sDao = new LoginDAL.SocreDAO();
sDao.UpdateScore(user.ID ,userName, 10);//增加積分
return user;
}
else
{
throw new Exception("登錄失敗");
}
}
}
DAL層:
class DBUtil
{
public static string ConnString = @"Server= (Local);Database=Login;User ID=sa;Password=123";
}
public class SocreDAO
{
public void UpdateScore(int ID,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)";
cmd.Parameters.Add(new SqlParameter("@ID", ID));
cmd.Parameters.Add(new SqlParameter ("@UserName",userName ));
cmd.Parameters.Add(new SqlParameter("@Score", value ));
conn.Open();
//執行sql句,返回受影響行數
cmd.ExecuteNonQuery();
}
}
}
public class UserDAO
{
public LoginModel.UserInfo SelectUser(string userName, string password)
{
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));
cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password "; //設置操作語句
conn.Open();//打開連接
//創建數據讀取對象,循環讀取數據
SqlDataReader reader = cmd.ExecuteReader(); //此方法用於用戶進行的查詢操作,使用SqlDataReader對象的Read();方法進行逐行讀取。
LoginModel.UserInfo user = null;
while (reader.Read())
{
if (user==null)
{
user = new LoginModel.UserInfo();
}
user.ID =reader.GetInt32(0); //獲取指定列的32位有符號整數形式的值
user.UserName = reader.GetString(1);
user.Password = reader.GetString(2);
if (!reader.IsDBNull (3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
實體層:
//數據模型,用於三層之間傳輸數據
public class UserInfo
{
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
原文鏈接:https://blog.csdn.net/duyusean/article/details/70882262