天天看點

三層架構--理論與實踐一.理論篇:二.實踐篇三.總結

    看視訊的時候,開篇提出了很多的問題,這讓我想起了“門衛定理”,你從哪裡來,要到那裡去,去幹什麼。學習本身就是這樣,提出問題比解決問題更重要,帶着問題學習,就會更加有目的性,注意力更集中。

一.理論篇:

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 [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>
           

三.總結

    了解三層,體會分層結構與不分層的差別和優勢。加深對面向對象的思想的認識,實作解耦,懂得化難為簡。理論結合實踐,将分層做到靈活運用,不為分層而分層,不為模式而模式;