三層架構--理論與實踐
看視訊的時候,開篇提出了很多的問題,這讓我想起了“門衛定理”,你從哪裡來,要到那裡去,去幹什麼。學習本身就是這樣,提出問題比解決問題更重要,帶著問題學習,就會更加有目的性,注意力更集中。
一.理論篇:
1.三層架構是什麼?有那三層,他們的順序?
三層架構是基於模組化程式設計的思想,為實現分解應用程式的需求,而逐漸形成的一種標準模式的模組劃分方法。從上到下分別是表現層(Presentation layer),業務邏輯層(Business
Logic Layer),資料訪問層(Data access layer)。所謂三層體系結構,是在客戶端與資料庫之間加入了一個“中間層”
2.每一層的含義和功能,為什麼分三層?
表現層:位於最外層(最上層),最接近使用者。用於顯示資料和接收使用者輸入的資料,為使用者提供一種互動式操作的介面。
UI設計原則是使用者至上,兼顧簡潔。
業務邏輯層:表示層和資料訪問層之間溝通的橋樑,主要負責資料的傳遞和處理
從DAL中獲取資料,以供UI顯示用
從UI中獲取使用者指令和資料,執行業務邏輯
從UI中獲取使用者指令和資料,通過DAL寫入資料來源
職責機制
UI->BLL->UI
UI->BLL->DAL->BLL->UI
資料訪問層:也稱為是持久層,其功能主要是負責資料庫的訪問,可以訪問資料庫系統、二進位制檔案、文字文件或是XML文件。
從資料來源載入資料(Select)
向資料來源寫入資料(Insert/Update)
從資料來源刪除資料(Delete)
三層的目的是實現“高內聚,低耦合”的思想,各層之間相互依靠介面連線,每一層的改變對其他層不會造成影響。
這樣做的好處有:
1.開發團隊可以明確分工,統一程式碼格式,並行開發,提高效率。
2.提高了系統的複用性,通過介面連線。
3.使得系統更加健壯,系統的易於維護,如果一層出現了問題,只需要維護該層就可以了,同樣降低了維護的成本。
4.分層之後讓系統更加清晰,把整體複雜的問題簡單化。
3.什麼時候需要三層?
並不是所有的系統都要分三層或多層。任何事情都有兩面性。過多的分層限制了限制了客戶與開發人員的交流。由於層與層之間的引用關係,程式碼執行效率降低,會對系統的效能造成影響。 專案開發中具體問題要具體分析,盲目套用耦合反而會適得其反,不應分層而分層,不應模式而模式。對於業務邏輯簡單,沒有資料儲存層的系統,就沒有必要分層。
4.每一層的原則與層與層之間的引用?
DAL,BLL,UI分別在不同的程式集中。各層之間的引用關係如下:
DAL所在程式集不引用BLL和UI
BLL引用DAL
UI直接引用BLL,可能間接引用DAL
三層都引用實體層。
5.實體層怎麼理解?
實體層為了封裝資料,為了資料在三層之間傳輸;對於大量的資料來說,用變數做引數不太合適 比如 把某個學生的所有資訊傳到下層,包括姓名 年齡 學號 班級...如果拿變數做引數,那在你的方法中起碼有N個引數,很容易造成引數匹配上的錯誤,而如果拿實體物件做引數則方便的多,只要傳一個學生實體就可以了,然後在方法裡通過get(),set()屬性獲取或者設定實體物件裡的成員屬性值 。
實體物件實際上是對應著資料庫裡的每張表的,我們把表裡的欄位封裝在1個實體物件裡,當想用哪個欄位 ,就通過該實體物件的get() set() 把那個欄位提取出來。這比臨時建立1個變數要靈活的多,而且便於程式的維護和擴充套件。
Model不知道外面的其他層次,獨立於其他層次,不會引用任何層次的程式集。其他的三層都會引用Model,都知道Modul的存在;
二.實踐篇
1.設計資料庫Login:
資料表 |
主鍵 | 列名 | 資料型別 | 允許Null值 |
dbo.Scores | 是 | ID | int | |
UserName |
varchar(50) |
|||
Score |
int |
|||
dbo.Users |
是 |
ID |
int |
|
UserName |
varchar(50) |
|||
PassWord |
varchar(50) |
|||
Email |
varchar(100) |
允許 |
2.程式碼:
UI層
<span style="font-family:Courier New;font-size:14px;">namespace LoginUI</span><span style="font-size:14px;"><span style="font-family:Courier New;">
{
public partial class Form1 : Form //Partial:區域性型別允許我們將一個類、結構或介面分成幾個部分,分別實現在幾個不同的.cs檔案中。各個部分可以再不同的原始檔中,原始檔要有相同的名稱空間;
{
public Form1()
{
InitializeComponent();<span style="white-space:pre"> </span>//初始化控制元件;
}</span><span style="font-family:System;">
</span></span><span style="font-family:Courier New;font-size:14px;">
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(); //例項化,開始轉到BLL中。UI呼叫BLL層;
//mgr.Login(UserName ,PassWord );
try //異常處理程式,將可能發生例外的程式碼放到Try語句中,catch捕捉例外。與On error goto的不同點
{
Login.Model.UserInfo user = mgr.UserLogin(UserName, PassWord);
MessageBox.Show("登入使用者:" + user.UserName);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}</span><span style="font-size:18px;">
</span>
BLL層
<span style="font-family:Courier New;font-size:14px;">namespace Login.BLL
{
public class LoginManager //類要設定為共有的才能訪問;
{
public Login.Model .UserInfo UserLogin (string UserName, string PassWord) //User就是一個資料模型;上竄下蹦;需要額外的建程式集;//返回Model的UserInfo;
{
//throw new NotFiniteNumberException();
//Login.DAL .UserDAO uDAO =new Login .DAL.UserDAO ();
//uDAO.SelectUser(UserName, PassWord);
Login.DAL.UserDAO uDAO = new Login.DAL.UserDAO(); //類例項化一個物件;
Login.Model.UserInfo user = uDAO.SelectUser(UserName, PassWord);
if (user != null) //登入成功
{
Login.DAL.ScoreDAO sDAO = new Login.DAL.ScoreDAO();
sDAO.UpdateScore(UserName, 10); //加10
return user;
}
else
{
throw new Exception("登入失敗"); //丟擲異常
}
}
}
}</span>
DAL層
<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
public class UserDAO
{
public Login.Model .UserInfo SelectUser(string UserName, string PassWord) //檢驗使用者存在不存在,登入是否成功。“資料模型”
{
//throw new NotImplementedException();
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; //指定如何解釋命令字串,text表示SQL 文字命令。
cmd.Parameters.Add(new SqlParameter("@UserName", UserName));
cmd.Parameters.Add(new SqlParameter("@PassWord", PassWord));
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(); //針對 Connection 執行 CommandText,並生成 IDataReader。
Login.Model.UserInfo user = null;
while (reader.Read()) //.Read()使 IDataReader 前進到下一條記錄。
{
if (user == null)
{
user = new Login.Model.UserInfo();
}
user.ID =reader.GetInt32(0);
user.UserName = reader.GetString(1);
user.PassWord = reader.GetString(2);<span style="white-space: pre;"> </span>//不需要從資料庫中取;
if (!reader.IsDBNull(3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
}</span><span style="font-size:18px;">
</span>
連線字串
<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
class DbUtil //連線字串
{
public static string ConnString = @"Server=fxq-PC;database=Login;user ID =sa ;PassWord=fxq";
}
}</span>
登入成功則資料庫中加10
<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
public class ScoreDAO
{
public void UpdateScore(string UserName, int Value)
{
//throw new NotFiniteNumberException();
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))<span style="white-space: pre;"> //using的程式碼範圍內你能使用conn這個物件,一旦你超出了using的程式碼範圍,就沒有conn可用;</span>
{
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(); //不用關閉,因為用了Using。相當於在using塊結束的時候手動呼叫conn.Dispose()方法</span><span style="font-family:Courier New;font-size:14px;">
cmd.ExecuteNonQuery(); //對連線執行 Transact-SQL 語句並返回受影響的行數。
}
}
}
}</span>
Entity(Model):為了封裝資料,為了資料在三層之間傳輸;Model不知道外面的其他層次,獨立於其他層次,不會引用任何層次的程式集。其他的三層都會引用Model,即都知道Modul的存在;
<span style="font-family:Courier New;font-size:14px;">namespace Login.Model
{
public class UserInfo
{ //.NET3.0以後支援的寫法;
//public int ID { get; set; }
//public string UserName{get ;set;}
//public string PassWord { get; set; }
//public string Email { get; set; }
private int _ID;<span style="white-space: pre;"> </span>//更加安全;
private string _UserName;
private string _PassWord;
private string _Email;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
public string UserName
{
set { _UserName = value; }
get { return _UserName; }
}
public string PassWord
{
set { _PassWord = value; }
get { return _PassWord; }
}
public string Email
{
set { _Email = value; }
get { return _Email; }
}
}
}</span><span style="font-size:18px;">
</span>
三.總結
瞭解三層,體會分層結構與不分層的區別和優勢。加深對物件導向的思想的認識,實現解耦,懂得化難為簡。理論結合實踐,將分層做到靈活運用,不為分層而分層,不為模式而模式;
相關文章
- Vue微前端架構與Qiankun實踐理論指南Vue前端架構
- MVC專案實踐,在三層架構下實現SportsStore,從類圖看三層架構MVC架構
- MVC 與三層架構MVC架構
- 三層架構與養豬架構
- 談理論與實踐
- MVC專案實踐,在三層架構下實現SportsStore-02,DbSession層、BLL層MVC架構Session
- MVC與三層架構區別MVC架構
- https理論與實踐HTTP
- 三層架構及分層架構
- 三層架構理解架構
- 詳解Diffusion擴散模型:理論、架構與實現模型架構
- js正則理論與實踐JS
- 理解RESTful:理論與最佳實踐REST
- 【架構與設計】常見微服務分層架構的區別和落地實踐架構微服務
- net三層架構與MVC的區別架構MVC
- 耦合層:撮合物聯網的理論與實踐牽手的“月老”
- Java三層架構sshJava架構
- .Net三層架構 (轉)架構
- 從理論到實踐,設計一款遊戲數值架構遊戲架構
- 關於三層架構中各層次的關係與實現模型 (轉)架構模型
- Asp.net 2.0三層架構的構建與理解ASP.NET架構
- Serverless 架構演進與實踐Server架構
- MVC專案實踐,在三層架構下實現SportsStore-05,實現導航MVC架構
- MVC專案實踐,在三層架構下實現SportsStore-04,實現分頁MVC架構
- MVC專案實踐,在三層架構下實現SportsStore-01,EF Code First建模、DAL層等MVC架構
- 軟體架構分層方法論架構
- MVC專案實踐,在三層架構下實現SportsStore-07,實現訂單提交MVC架構
- MVC專案實踐,在三層架構下實現SportsStore-06,實現購物車MVC架構
- Node直出理論與實踐總結
- Java 理論與實踐: 併發集合類Java
- 深入解析Rivest Cipher 4:理論與實踐
- 雙目標定與三維計算:從理論到OpenCV實踐OpenCV
- Java 理論與實踐: 關於異常的爭論Java
- 密碼學與密碼安全:理論與實踐密碼學
- Golang實時GC的理論與實踐總結GolangGC
- 傳引數與傳實體、返回實體與返表——三層架構登入例項架構
- 三層架構是什麼意思 ?架構
- 說說三層架構和MVC架構MVC