淺談三層架構 通過這個,+Java開發模式經驗。終於相通了,動軟到底是為什麼這麼做...

weixin_34377065發表於2011-05-12

淺談三層架構 收藏

自己理解的原理

http://www.cnblogs.com/mahaisong/archive/2011/05/12/2044665.html

 

 

 

淺談三層架構  通過這個,+Java開發模式經驗。終於相通了,動軟到底是為什麼這麼做。

,NET開發兩個專案了。半年了。一直沒搞懂。為什麼。net的三層是這樣的。原來今天這裡的三層是這樣的啊?

 

BLL 做業務邏輯。 DAL 做 資料操縱。    第三次是 介面層(codeBehind).

這就是三層。和JAVA沒什麼不同。只不過。我一直在糾結。為什麼 MVC 要這樣分。其實我錯了。MVC 是最基礎,然後再分成三層。為什麼這麼說那。

MVC。M(Model)-V(View)-C(Control)。 我們一般做操作就把COntorl 做成一個操作的封裝就O了。

而如果開闢大局觀的物件導向的話。  Model是資料的物件核心。    而操作的核心 因為 物件導向的 思想。進行各種介面化 (自動選擇對應的資料庫。封裝的概念。)  這樣就把物件導向 超越編碼 提高到了架構上了。

 

因此。這裡它還增加了一個工廠模式。

 

 

我這裡分析一下。  Bll 做業務邏輯。

private readonly IActivityComment dal=DataAccess.CreateActivityComment();

利用 介面

public sealed class DataAccess
{
    private static readonly string AssemblyPath = ConfigurationManager.AppSettings["DAL"];

//不使用快取
private static object CreateObjectNoCache(string AssemblyPath, string classNamespace)
{
    try
    {
        object objType = Assembly.Load(AssemblyPath).CreateInstance(classNamespace);
        return objType;
    }
    catch//(System.Exception ex)
    {
        //string str=ex.Message;// 記錄錯誤日誌
        return null;
    }

}
//使用快取

/// <summary>
    /// 建立ActivityComment資料層介面
    /// </summary>
    public static database.IDAL.IActivityComment CreateActivityComment()
    {

        string ClassNamespace = AssemblyPath + ".ActivityComment";
        object objType = CreateObject(AssemblyPath, ClassNamespace);
        return (database.IDAL.IActivityComment)objType;
    }

 

利用反射,反射到SQLSERVERDAL,得到資料,封裝到介面中。 而Bll中的方法,和IDAL的方法是對應的關係(大多數)。因為為了封裝,就利用BLL中的方法呼叫實際的IDAL中的方法。(反射,委託,事件,在三個的存在+更高層次的物件導向是 真正難理解的地方。)

 

 

 

每天思考深一點三層。終身受益。

 

 

 


三層架構並不是MVC,MVC是一個很早就有的經典的程式設計模式,M-V-C分為三層,M(Model)-V(View)-C(Control)。而web開發中的三層架構是指:資料訪問層(DAL-DatabaseAccessLayer),業務邏輯層(BLL-BusinessLoginLayer),以及使用者介面層(UI-UserInterface,實際就是網頁後臺的具體呼叫BLL層)。這個是基本概念。曾經我以為三層架構就是在AppCode中,分為三個大類與若干小類,各司其職。在經過一番洗禮後,才發覺多麼的無知。

首先AppCode中,放的是通用類,如資料庫通用類,實現資料庫連線,基本的SqlCommand建立,自定義CRUD的方法等,與三層架構毫無關係,就是常用的開發模式中存放類(Class)的資料夾。

其次,當使用三層架構時,一定是在大專案中,因為三層架構的目的是提高專案的鬆散性和降低專案的耦合度,使之更容易擴充套件或者維護。小專案使用了三層架構,由於過度的在意分層而導致了專案的複雜度增加。

建立三層架構的應用程式。我們必須對這三層分別建立不同的類庫(ClassLibrary),而不是普通的類(Class)。我們對於任何一個模組或者功能進行OOP,把它擴充套件為物件(物件導向的思想就是:將所操作的目標當成一個物件,對它進行的操作,將由物件自己的方法進行,而非外界傳參。譬如註冊使用者,用程式導向的方法事先,就是:public static bool Register(string userName, string userPwd)。若用OO的思想,我們不可將賬號密碼作為引數傳入,而是將使用者作為一個物件,這個物件具有private _userName,和private _userPwd的屬性。在註冊時,用建構函式初始化一個新的物件,User one = new User(userName,userPwd),使之在初始化後具有這兩個欄位的值。然後呼叫User類中的public static bool Register()方法(注意這個方法是不進行傳參的),而在這個Register方法中,使用物件的_userName和_userPwd屬性進行註冊。),那麼,我們在這個物件中的任何操作都將以該物件的方法(函式)實現。

在進行三層分類時,這樣新建類庫。

1.檔案->新建專案->其他專案型別->空白解決方案。

2.在右側的“資源管理器”中,選中當前解決方案,右鍵新增->新建專案->類庫(ClassLibrary),分別建立BLL,DAL,UL類庫。(若新增後看不到解決方案則在選單->工具->選項->專案和解決方案->總是顯示解決方案)。

3.右鍵,向解決方案中新增一個網站(新網站或者現有網站)。

4.根據需求刪除或者保留預設新增項(預設的class1.cs或Default.aspx檔案)。

這樣一個三層架構的網站雛形就搭建好了。因為UI層要被其他兩層引用,DAL層要被BLL層引用。所以需要相互新增引用,方法是在類庫上點選右鍵->新增引用->專案->選擇其他類庫。並且在具體類中引入名稱空間(using namespace)。

ps:類庫其實就是類的集合,三層架構的目的就是,將同一專案的不同模組都劃分為各自的三層,各司其職,將具體實現方法用類寫出,新增到該層的類庫中,這樣,一個網站下的類庫就只有三層,每一層中都包含了各個模組相對應層的實現方法。在以後修改或擴充套件時,在對應層中進行操作就可以了。

一般的專案,涉及最多的就是對資料庫的CRUD,DAL層只負責與資料庫的互動,BLL層是最重要的一層,他負責將DAL層的的結果呈現給UI層,但是恰恰BLL層的存在似乎有點雞肋,他起到的僅僅是轉發DAL層資料的作用,而具體的邏輯操作是與資料庫的互動,應該寫在DAL層,這就好像BLL層是在重複DAL層的勞動一樣,其實BLL層的作用在於除了呼叫DAL層訪問資料庫,還可以進行邏輯判斷,當符合的時候,才進行允許進行DAL的操作,或者進行額外的操作(如加密,轉換等)。而DAL層可不管這些,他只管進行CRUD的動作。UI層就是操作抽象出來的實體物件,它包含了各種屬性。

在這裡我說一下。簡單三層的架構:WEB,BLL ,DAL做主框架。而MOdel 因為物件導向+每層都用。所以獨立出來。和DAL並列。

解密,快取,資料校驗,因為是通用,也單獨分離。放在Common類中。而,資料庫訪問類,因為資料庫的多種多樣,所以有一個 通用的資料庫操作類。叫做DBUtility 獨立出來,專門做 資料庫訪問的,(例如,反射後自動區分是訪問EXCEL還是SQL),與Common並列。

DBUtility是對ADO.NET的封裝,封裝了一些常用的重複的資料庫操作。 如微軟的SQLHelper。cs  或動軟的DBUtility/DbHelperSQL等,為DAL提供訪問資料庫的輔助工具類。

 

這樣簡單三層出來了。 所以有兩個資料夾  database 和utility;

database 下有 BLL和 DAL。因為WEB 程式(aspx或jsp)是表示層。所有不放這裡。

utility 下有 Common 類和 DBUtility 類。Common 類是通用的輔助工具類。

 DBUtility 類是資料訪問類。

而WEB 中aspx頁面Using 對應的 database 中的類。是因為。引用了。才能用啊。  而引用程式集。可以在 “引用”--“右鍵” 新增引用中做。 

 

 

如果想再瞭解。請見下一篇轉載的大話簡單三層。

 

 

 

 

 

 

一個三層架構的小例子:註冊新使用者。

先寫模組的實體類,是資料庫中表的抽象,假設資料庫中註冊資訊只有賬號,密碼兩個欄位。那麼抽象到實體類就是這樣:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
namespace Entity  
{  
    class UserInfo  
    {  
        public string UserName { get; set; }    //C#3.0中屬性構造器的新寫法;  
        public string UserPwd { get; set; }  
    }  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Entity
{
    class UserInfo
    {
        public string UserName { get; set; }    //C#3.0中屬性構造器的新寫法;
        public string UserPwd { get; set; }
    }
}

再寫DAL層:

using System;   using System.Collections.Generic;   using System.Linq;   using System.Text;   using System.Data;   using System.Data.SqlClient;   using Entity;   //這裡新增對Entity實體類的引用;   namespace DAL   {       public class UserDAL       {           //在該類中,為了方便,一般會構造一個DataBaseFactory,方便進行程式碼的操作。所以以下程式碼僅為邏輯實現,不代表程式碼正確。           public bool AddUser(UserInfo uInfo) //這裡將實體類作為引數傳入;           {               string sqlStr="INSERT INTO UserInfo(Name,Pwd) VALUES(@name,@pwd)";               SqlCommand cmd=new SqlCommand(sqlStr);               cmd.Parameters.Clear();               cmd.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = uInfo.UserName; //呼叫實體類的屬性               cmd.Parameters.Add("@pwd", SqlDbType.NVarChar, 50).Value = uInfo.UserPwd;               return Convert.ToInt32(cmd.ExecuteNonQuery()) > 0 ? true : false;           }           public DataTable GetUserInfo(string name)   //根據使用者名稱獲得使用者的具體資訊           {               string sqlStr="SELECT * FROM UserInfo WHERE Name=@name";               SqlCommand cmd=new SqlCommand(sqlStr);               cmd.Parameters.Clear();               cmd.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = name;               SqlDataAdapter sda = new SqlDataAdapter(cmd);               DataSet ds=new DataSet();               sda.Fill(ds,"UserInfo");               return ds.Tables["UserInfo"];           }       }   }  using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Entity;   //這裡新增對Entity實體類的引用;
namespace DAL
{
    public class UserDAL
    {
        //在該類中,為了方便,一般會構造一個DataBaseFactory,方便進行程式碼的操作。所以以下程式碼僅為邏輯實現,不代表程式碼正確。
        public bool AddUser(UserInfo uInfo) //這裡將實體類作為引數傳入;
        {
            string sqlStr="INSERT INTO UserInfo(Name,Pwd) VALUES(@name,@pwd)";
            SqlCommand cmd=new SqlCommand(sqlStr);
            cmd.Parameters.Clear();
            cmd.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = uInfo.UserName; //呼叫實體類的屬性
            cmd.Parameters.Add("@pwd", SqlDbType.NVarChar, 50).Value = uInfo.UserPwd;
            return Convert.ToInt32(cmd.ExecuteNonQuery()) > 0 ? true : false;
        }
        public DataTable GetUserInfo(string name)   //根據使用者名稱獲得使用者的具體資訊
        {
            string sqlStr="SELECT * FROM UserInfo WHERE Name=@name";
            SqlCommand cmd=new SqlCommand(sqlStr);
            cmd.Parameters.Clear();
            cmd.Parameters.Add("@name", SqlDbType.NVarChar, 50).Value = name;
            SqlDataAdapter sda = new SqlDataAdapter(cmd);
            DataSet ds=new DataSet();
            sda.Fill(ds,"UserInfo");
            return ds.Tables["UserInfo"];
        }
    }
}

再寫BLL層:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Data;  
using Entity;   //新增對Entity類庫的引用  
using DAL;  //新增對DAL類庫的引用  
namespace BLL  
{  
    public class UserBLL  
    {  
        public static bool AddUser(UserInfo uInfo)  //BLL層的方法多為靜態方法,DAL層也可以為靜態方法。  
        {  
            UserDAL uDal = new UserDAL();  
            DataTable dTable = uDal.GetUserInfo(uInfo.UserName);  
            if (dTable.Rows.Count > 0)  //這裡對註冊使用者有一個判斷,從DAL層中先通過註冊名獲得使用者的具體資訊,若可以獲得則證明該使用者名稱已被註冊,返回false;  
                return false;  
            else 
                return uDal.AddUser(uInfo);  
        }  
    }  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Entity;   //新增對Entity類庫的引用
using DAL;  //新增對DAL類庫的引用
namespace BLL
{
    public class UserBLL
    {
        public static bool AddUser(UserInfo uInfo)  //BLL層的方法多為靜態方法,DAL層也可以為靜態方法。
        {
            UserDAL uDal = new UserDAL();
            DataTable dTable = uDal.GetUserInfo(uInfo.UserName);
            if (dTable.Rows.Count > 0)  //這裡對註冊使用者有一個判斷,從DAL層中先通過註冊名獲得使用者的具體資訊,若可以獲得則證明該使用者名稱已被註冊,返回false;
                return false;
            else
                return uDal.AddUser(uInfo);
        }
    }
}

最後構建UI層程式碼,即我們的aspx.cs頁面程式碼,該層應該直接呼叫BLL層的方法。該頁面引用BLL和Entity的名稱空間,並向Button控制元件註冊事件:

protected void btnRegister_OnClick(object sender, EventArgs e)  
       {  
           UserInfo uInfo = new UserInfo(textUserName.text, textUserPwd.text);  
           if (UserBLL.AddUser(uInfo))  
               Response.Write("註冊成功!");  
           else 
               Response.Write("註冊失敗!");  
       } 
protected void btnRegister_OnClick(object sender, EventArgs e)
        {
            UserInfo uInfo = new UserInfo(textUserName.text, textUserPwd.text);
            if (UserBLL.AddUser(uInfo))
                Response.Write("註冊成功!");
            else
                Response.Write("註冊失敗!");
        }

這樣一個小的三層架構程式就出來了。

這個程式中,操作的實體為UserInfo表的抽象。在DAL層進行了AddUser()的方法,在BLL層也進行了AddUser()的方法,唯一的區別是BLL層做了邏輯判斷,如果使用者名稱存在,則註冊失敗。

三層架構的特點:

1.資料庫訪問層(DAL)僅提供對資料庫的CRUD操作,而不管操作後的結果,也不管邏輯過程(譬如同名使用者,不合法使用者名稱)。

2.業務邏輯層(BLL)不會直接與資料庫互動,他與資料庫的互動是通過DAL提供的方法。在呼叫這些方法前,要加入自己的邏輯判斷或者業務處理。另外業務邏輯層(BLL)還有可能不會去呼叫DAL層的方法,而是進行其他業務處理。

 

3.使用者介面層(UI)層是不會呼叫DAL層的,他只呼叫BLL層提供的方法,再由BLL層自己決定是否繼續呼叫DAL層。

 

這個例子可以看出三層架構的優點就是結構清晰,容易擴充套件與維護。缺點就是,複雜。僅僅一個註冊使用者,就這麼麻煩,所以對於小專案來說,費這麼大勁換取一個相對較清晰的分層結構是不划算的。

轉載請註明出處:csdn-mark

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/mark4ever/archive/2011/04/05/6302353.aspx  有一部分,也是我自己添的哈。嘿嘿

相關文章