看視訊的時候,開篇提出了很多的問題,這讓我想起了“門衛定理”,你從哪裡來,要到那裡去,去幹什麼。學習本身就是這樣,提出問題比解決問題更重要,帶着問題學習,就會更加有目的性,注意力更集中。
一.理論篇:
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) | |||
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 [email protected] AND PassWord [email protected]";
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>
三.總結
了解三層,體會分層結構與不分層的差別和優勢。加深對面向對象的思想的認識,實作解耦,懂得化難為簡。理論結合實踐,将分層做到靈活運用,不為分層而分層,不為模式而模式;