程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 三層架構,三層架構和mvc的區別

三層架構,三層架構和mvc的區別

編輯:C#入門知識

三層架構,三層架構和mvc的區別


在網上收集的比較好的講解三層架構的理解,我收集兩部分,第一部分簡單理解,第二部分比較詳細。也有一些重復的地方

一、

C#三層架構登陸實例

 

很早之前,就聽說過三層結構了。當時只知道 三層結構 是把 系統的 界面 跟 數據庫操作等不相關的程序分別開來。原來這麼簡單的實現,確實傳說中的 三層結構啊。

首先,先來看一下是哪三層。表示層(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();

            }

        }

    }

}

接下來,看一下執行結果:

執行成功的情況:

 

輸入錯誤信息:

 

雖然這是一個很小的實例,但是用來學習三層卻足夠了。有寫的不好的地方可以理解。

總結:對於使用三層架構的程序來說,哪層出錯改哪裡。極大程度的降低了系統的耦合性。當然,具有層次的程序,維護起來必然要方便許多。

 -------------------------------------------------------------------------------------------------------------------------

二、

理解C#中得三層架構

       

  • 表示層
  • 業務邏輯層(BLL)
  • 數據訪問層(DAL)

關聯:產生依賴關系

描述:三層體系結構就是在客戶端和數據庫之間加一個中間層,通常情況下客戶端不能直接和數據庫進行交互,而是通過中間層和數據層進行交互的。

  【表示層】

    主要負責完成用戶和系統的交互。

    它接收用戶輸入的信息,並把上級傳來的處理結果表示給用戶。蓋層有時候兼容一小部分業務邏輯層的作用(驗證用戶輸入的數據及其合法性)

    一般作為Windows或者Web應用程序

  【業務邏輯層】

    接收表示層傳來的數據,以參數的形式傳給數據訪問層;然後接收數據層發來的處理好的數據,傳給表示層。

    該層所做的工作比較復雜,如:實現業務流程、業務的數據校驗

    是表示層和數據層之間的橋梁,都需要通過業務邏輯層來完成信息數據的收發

  【數據訪問層】

    數據訪問層為系統提供了規范,統一數據的訪問入口,保證業務邏輯層對系統數據訪問層的規范和高效,從而實現數據被高效、安全的訪問

    該層會根據業務邏輯層的請求去處理和數據庫之間的交互,不對數據做任何業務上的加工

【本人見解】

  表示層接受用戶的請求,根據用戶的請求去通知業務邏輯層,業務邏輯層收到請求,首先對請求進行審核,然後將請求發給數據訪問層或者直接返回到表示層,數據訪問層收到請求後就開始訪問數據庫,數據訪問層通過數據庫的訪問得到請求的結果,並把結果通知業務邏輯層,業務邏輯層收到請求結果將請求結果通知表示層,表示層收到請求結果,然後把結果顯示給用戶;

  ps:用戶登錄系統就是這一應用的實例。

    用戶輸入賬號密碼---->表示層先判斷,符合----->業務邏輯層進行封裝--------->數據訪問層進行進一步安全、高效的判斷------->結果給業務邏輯層------->表示層顯示結果

    這種傳遞是一步一步的進行下去,一步一步的回來,不能跨越傳遞。

 

 

在三層之間,各層之間是相互依賴的關系的,表示層依賴業務層邏輯,業務層依賴數據訪問層,三層之間通過自身提供的對外方法來傳遞訪問

三層之間的松耦合互不干擾,之間的聯系是通過自己提供的接口來訪問;

三層結構各層之間的的數據傳遞方法分為請求和響應兩個方法;

項目依賴方向:先從表示層傳遞到業務層再到數據層;

數值返回:數據層返回給業務邏輯層,在由業務邏輯層返回給表示層,然後由表示層進行顯示;

------------------------------------------------------------------------------------------

三層架構(我的理解及詳細分析)

1什麼是三層

三層架構已經學了一段時間,一直想做一個比較完整、比較完美的總結。但是左思右想,不知道如何下筆。都說萬事開頭難嘛,今天整理了一下凌亂的思路,哎,還是沒整理好,想到哪就說到哪吧。

 

初學者很不理解:

1,什麼是三層?

2,為什麼使用三層?

3,三層與以往使用的兩層相比有什麼不同?它的優勢在哪裡?

4,如何學好三層?如何應用三層?

……

這篇博客裡我會給大家一一解釋一下,略懂皮毛忘大家見諒!!!

米老師一直強調:讓學習和生活結合,把學習和生活聯系,這樣的學習才叫會學習,會生活。

對於三層我左思右想,如何與實際相聯系。好嘛,昨晚突然有了“靈感”。還記得大話設計模式裡第23章大鳥和小菜吃羊肉串的故事——由在小攤吃到飯店吃引來的一個命令模式(當然今天不是研究命令模式)。服務員、廚師、采購員。

這不就是個典型的三層架構嗎???(⊙ o ⊙ )啊!哈哈(這個後面再做解釋)

 

 

 

先了解:

 

1,什麼是三層?

UI(表現層):主要是指與用戶交互的界面。用於接收用戶輸入的數據和顯示處理後用戶需要的數據。

 

BLL:(業務邏輯層):UI層和DAL層之間的橋梁。實現業務邏輯。業務邏輯具體包含:驗證、計算、業務規則等等。

 

DAL:(數據訪問層):與數據庫打交道。主要實現對數據的增、刪、改、查。將存儲在數據庫中的數據提交給業務層,同時將業務層處理的數據保存到數據庫。(當然這些操作都是基於UI層的。用戶的需求反映給界面(UI),UI反映給BLL,BLL反映給DAL,DAL進行數據的操作,操作後再一一返回,直到將用戶所需數據反饋給用戶)

 

每一層都各負其責,那麼該如何將三層聯系起來呢?

1>單項引用(見下圖)

2>這時候實體層(Entity)來了。(注:當然,實體層的作用不止這些)

 

Entity(實體層):它不屬於三層中的任何一層,但是它是必不可少的一層。

 

Entity在三層架構中的作用:

1,實現面向對象思想中的"封裝";

2,貫穿於三層,在三層之間傳遞數據;

注:確切的說實體層貫穿於三層之間,來連接三層)

3,對於初學者來說,可以這樣理解:每張數據表對應一個實體,即每個數據表中的字段對應實體中的屬性(注:當然,事實上不是這樣。為什麼?1>,可能我們需要的實體在數據表對應的實體中並不存在;2>,我們完全可以將所有數據表中的所有字段都放在一個實體裡)

4,每一層(UI—>BLL—>DAL)之間的數據傳遞(單向)是靠變量或實體作為參數來傳遞的,這樣就構造了三層之間的聯系,完成了功能的實現。

但是對於大量的數據來說,用變量做參數有些復雜,因為參數量太多,容易搞混。比如:我要把員工信息傳遞到下層,信息包括:員工號、姓名、年齡、性別、工資....用變量做參數的話,那麼我們的方法中的參數就會很多,極有可能在使用時,將參數匹配搞混。這時候,如果用實體做參數,就會很方便,不用考慮參數匹配的問題,用到實體中哪個屬性拿來直接用就可以,很方便。這樣做也提高了效率。

 

注:這裡為什麼說可以暫時理解為每個數據表對應一個實體??答:大家都知道,我們做系統的目的,是為用戶提供服務,用戶可不關心你的系統後台是怎麼工作的,用戶只關心軟件是不是好用,界面是不是符合自己心意。用戶在界面上輕松的增、刪、改、查,那麼數據庫中也要有相應的增、刪、改、查,而增刪改查具體操作對象就是數據庫中的數據,說白了就是表中的字段。所以,將每個數據表作為一個實體類,實體類封裝的屬性對應到表中的字段,這樣的話,實體在貫穿於三層之間時,就可以實現增刪改查數據了)

 

綜上所述:三層及實體層之間的依賴關系:

 

 

思想來源於生活:

 

 

 

服務員:只管接待客人;

廚師:只管做客人點的菜;

采購員:只管按客人點菜的要求采購食材;

 

他們各負其職,服務員不用了解廚師如何做菜,不用了解采購員如何采購食材;廚師不用知道服務員接待了哪位客人,不用知道采購員如何采購食材;同樣,采購員不用知道服務員接待了哪位客人,不用知道廚師如何做菜。

 

他們三者是如何聯系的?

比如:廚師會做:炒茄子、炒雞蛋、炒面——此時構建三個方法( cookEggplant()、cookEgg()、cookNoodle())

 

顧客直接和服務員打交道,顧客和服務員(UI層)說:我要一個炒茄子,而服務員不負責炒茄子,她就把請求往上遞交,傳遞給廚師(BLL層),廚師需要茄子,就把請求往上遞交,傳遞給采購員(DAL層),采購員從倉庫裡取來茄子傳回給廚師,廚師響應cookEggplant()方法,做好炒茄子後,又傳回給服務員,服務員把茄子呈現給顧客。

這樣就完成了一個完整的操作。

 

在此過程中,茄子作為參數在三層中傳遞,如果顧客點炒雞蛋,則雞蛋作為參數(這是變量做參數)。如果,用戶增加需求,我們還得在方法中添加參數,一個方法添加一個,一個方法設計到三層;何況實際中並不止設計到一個方法的更改。所以,為了解決這個問題,我們可以把茄子、雞蛋、面條作為屬性定義到顧客實體中,一旦顧客增加了炒雞蛋需求,直接把雞蛋屬性拿出來用即可,不用再去考慮去每層的方法中添加參數了,更不用考慮參數的匹配問題。

 

這樣講,不知道大家是不是可以明白。(待會實例解釋吧)

 

2,為什麼使用三層?

使用三層架構的目的:解耦!!!

同樣拿上面飯店的例子來講:

(1)服務員(UI層)請假——另找服務員;廚師(BLL層)辭職——招聘另一個廚師;采購員(DAL)辭職——招聘另一個采購員;

(2)顧客反映:1>你們店服務態度不好——服務員的問題。開除服務員;

2>你們店菜裡有蟲子——廚師的問題。換廚師;

 

任何一層發生變化都不會影響到另外一層!!!

 

3,與兩層的區別??

兩層:

 

 

(當任何一個地方發生變化時,都需要重新開發整個系統。“多層”放在一層,分工不明確耦合度高——難以適應需求變化,可維護性低、可擴展性低)

 

三層:

 

 

 

(發生在哪一層的變化,只需更改該層,不需要更改整個系統。層次清晰,分工明確,每層之間耦合度低——提高了效率,適應需求變化,可維護性高,可擴展性高)

 

綜上:三層架構的

優勢:1,結構清晰、耦合度低,2,可維護性高,可擴展性高;3,利於開發任務同步進行;容易適應需求變化

 

劣勢:1、降低了系統的性能。這是不言而喻的。如果不采用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。

2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼

3、增加了代碼量,增加了工作量

 

4,三層的具體表現形式??

 

 

UI

 

(大家不要誤會,UI層不只是一個個用戶界面,也是需要有代碼的)

 

 

(1,功能:用戶輸入數據、反饋給用戶數據;2,大家觀察代碼:沒有涉及到業務邏輯,直接傳參、函數、方法調用,沒有涉及到與數據庫打交道的SQL語句和ADO.NET)

 

BLL

 

 

(1,BLL是表示層與數據訪問層之間的橋梁,負責數據處理、傳遞;2,大家觀察代碼,沒有涉及到界面上的控件,沒有涉及到SQL語句和ADO.Net

 

DAL

 

 

 

 

 

 

 

 

(1,以上是DAL層中DbUtil類、user_DA類和workRecord_DA類中的代碼;2,大家觀察代碼,沒有涉及到界面控件,沒有涉及到業務邏輯;只有與數據庫打交道的SQL語句和ADO.net)

 

Entity(Model)層:

 

(定義了實體類user)

觀察以上三層:

1,實體類user作為參數貫穿於三層之間;

2,通過傳參、方法調用來實現功能;

3,各層之間各負其責;互不影響

 

對比兩層結構,讓大家深刻體會三層的極大好處:

還是以機房收費系統的登陸為例:

 

(觀察上面的兩層的代碼:將業務邏輯、數據訪問都展現在用戶表現層,當需求需要改變時,需要改變整個系統。比如,我把文本框txtPassWord的名稱改為txtPwd的話,大家觀察一下得需要更改多少地方。這樣的改動算是小的,如果真的有業務需求上的改動才叫麻煩復雜,程序員不跳樓才怪。呵呵、、開個玩笑)

與如此難以適應需求變化的兩層相比,大家再次觀察三層代碼,再次思考,三層架構有什麼好處呢?自己思考。。。。。

 

自己去發掘吧!!!

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved