劉軍華
(湖南郵電職業(yè)技術(shù)學(xué)院,湖南長沙410015)
Microsoft.Net Framework是微軟推出的一套新一代開發(fā)平臺。ASP.NET作為其中的一部分,其最大的優(yōu)點除了編譯執(zhí)行速度快外,還有一點就是頁面和代碼分離的編寫方式[1]。這就使得基于.NET平臺可以快速方便地部署B(yǎng)/S三層架構(gòu)Web應(yīng)用程序。然而,傳統(tǒng)的三層架構(gòu)之間一般是表示層引用業(yè)務(wù)邏輯層,業(yè)務(wù)邏輯層再引用數(shù)據(jù)訪問層。另外,在實際項目開發(fā)過程中,由于客戶需求的不確定性,很有可能會因為自身需要而經(jīng)常變化,這就使得程序員必須不停地改寫現(xiàn)有的業(yè)務(wù)代碼。這樣,就形成三個層次之間的依賴性太高,不便于實現(xiàn)層與層之間的可替換,而且還加大了軟件后期測試和維護的難度,影響系統(tǒng)本身的穩(wěn)定性。為了降低三層結(jié)構(gòu)系統(tǒng)中層與層之間的耦合度,增強系統(tǒng)的可拓展和可移植性,本文提出一種面向接口的編程思想應(yīng)用于三層架構(gòu)當(dāng)中,以實現(xiàn)層次之間的無縫結(jié)合,保證系統(tǒng)的通用性、標準化和數(shù)據(jù)庫的可移植性。
外界觀察任何一個對象,最主要關(guān)注對象提供了哪些服務(wù)。至于這些服務(wù)的功能是如何在對象內(nèi)部實現(xiàn)的,外界并不關(guān)心。對象所提供的服務(wù)就是對象所提供的操作,而操作就是方法。因此,對象中所有外界能使用方法集合,構(gòu)成了對象與外界進行交互的“界面”,即接口。簡單地講,接口就是一些方法特征的集合,但不提供實現(xiàn)方式。下面以消息顯示功能為例說明接口的定義:
public interface ITest{ //定義接口ITest
void show(string strMsg);//定義接口成員方法show
}
以上是定義一個測試接口,相當(dāng)于在程序中設(shè)置一個約定的業(yè)務(wù)規(guī)范。
由于接口只提供方法定義,不提供方法實現(xiàn)。一般交由繼承該接口的類去實現(xiàn),而一個接口可以被多個類繼承,因此,每一個類可以自由決定其實現(xiàn)方式的細節(jié),即是以不同的方式實現(xiàn)同一接口中的同名方法,使其具有完全不同的表現(xiàn)行為[2]。識別接口的代碼可以利用類的對象,因為接口對于這些對象是相同的。.NET允許充分利用“一個接口,多個方法”的多態(tài)性。如:
public class A:ITest
{public void show(string strMsg) {
Console.WriteLine(strMsg+“明天更美好!”);
}
}
public class B:ITest
{public void show(string strMsg) {
Console.WriteLine(strMsg+“明天更輝煌!”);
}
}
A、B類都實現(xiàn)了ITest的規(guī)范,但表示行為完全不同。使用.NET接口標識類型,程序運行時,將根據(jù)實際創(chuàng)建的對象類型調(diào)用相應(yīng)的方法實現(xiàn)。public class Program
{
static void Main(string[]args) {
#region沒有用接口時的一種做法
//A a=new A();
//a.show(“郵電事業(yè)”);
//B b=new B();
//b.show(“郵電事業(yè)”);
#endregion
#region有用接口時的一種做法
ITest test=new A();
test.show(“郵電事業(yè)”);
test=new B();
test.show(“郵電事業(yè)”);
#endregion
}
}
通過以上代碼可以清楚地看出,沒有使用接口時,編譯時可以通過方法調(diào)用對象的不同區(qū)分出調(diào)用哪個類中的show方法;而使用了接口之后,因為方法調(diào)用對象是同一個,所以必須在程序運行時,通過創(chuàng)建對象的類型來決定調(diào)用哪個類中的show方法。正因為接口的這一特點,為多層結(jié)構(gòu)之間的動態(tài)訪問成為現(xiàn)實,進一步提高了程序的靈活性。
傳統(tǒng)的三層架構(gòu)包括表示層、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層。示意圖如圖1所示。這樣做的目的就為了實現(xiàn)軟件的“高內(nèi)聚,低耦合”的架構(gòu)思想。每個層實現(xiàn)應(yīng)用程序一個方面的邏輯功能,通過層與層之間的交互,形成應(yīng)用程序體系架構(gòu),從而實現(xiàn)適應(yīng)于企業(yè)級應(yīng)用的、功能復(fù)雜的應(yīng)用程序[3]。
圖1 三層架構(gòu)示意圖
1)表示層:表示位于最外層,是離用戶最近的層。主要完成了兩個任務(wù):一是獲取數(shù)據(jù)并顯示,將從業(yè)務(wù)邏輯層中動態(tài)獲取的數(shù)據(jù)以適當(dāng)?shù)男问斤@示給用戶;二是接收數(shù)據(jù)并傳遞,將用戶從界面輸入的數(shù)據(jù)傳入業(yè)務(wù)邏輯層進行下一步的處理。
2)業(yè)務(wù)邏輯層:邏輯層是整個分層模型的中間層。主要負責(zé)處理所有來自表示層的用戶請求,并根據(jù)具體應(yīng)用將用戶請求進行組合,形成一種業(yè)務(wù)規(guī)則轉(zhuǎn)換為對數(shù)據(jù)訪問層的請求;同時,將數(shù)據(jù)訪問層返回的結(jié)果提交給表示層。
3)數(shù)據(jù)訪問層:數(shù)據(jù)訪問層是整個分層體系的最底層。主要實現(xiàn)對數(shù)據(jù)庫進行增刪查改操作。為業(yè)務(wù)邏輯層提供數(shù)據(jù)服務(wù),根據(jù)業(yè)務(wù)邏輯層的要求從數(shù)據(jù)庫中提取數(shù)據(jù)或者修改數(shù)據(jù)庫中的數(shù)據(jù)。由于訪問數(shù)據(jù)庫是系統(tǒng)中頻繁發(fā)生而且最消耗資源的操作,所以在這一層要對數(shù)據(jù)庫訪問進行優(yōu)化,提高系統(tǒng)的性能和可靠性[4]。
在傳統(tǒng)的三層體系結(jié)構(gòu)中,表示層依賴業(yè)務(wù)邏輯層,業(yè)務(wù)邏輯層依賴數(shù)據(jù)訪問層。例如,單擊表示層界面中某一測試按鈕,就將數(shù)據(jù)庫商品表中的最新10條記錄讀取并顯示在網(wǎng)格控件中。各層次參考代碼如下:
1) WEB表示層:protected BLL.Products pr=new BLL.Products();
protected void btnTest_Click(object sender,EventArgs e)
{ //獲取最新商品,顯示到newProducts控件中
DataTable dt=pr.getNewProducts();
newProducts.DataSource=dt;
newProducts.DataBind();
}
2)BLL業(yè)務(wù)層代碼片斷:class Products
{
public DataTable getNewProducts(){
string Sqlstr=”select top 10*from products order by id desc”;
DataTable dt=DBUtility.SQLHelper.ExecuteDT(Sqlstr);
return dt;
}
}
3)DBUtility數(shù)據(jù)訪問層代碼:class SQLHelper
{
public static DataTable ExecuteDT (string Sqlstr)
{
sring ConnStr=SQLHelper.GetSqlConnection();
using (sqlConnection conn=new sqlConnection(ConnStr)) {
sqlDataAdapter da=new sqlDataAdapter(Sqlstr,conn);
DataTable dt=new DataTable();
conn.Open();
da.Fill(dt);
return dt;
}
}
}
通過對上述代碼分析,可以看出層次之間的深度依賴,業(yè)務(wù)邏輯層直接調(diào)用數(shù)據(jù)訪問層的ExecuteDT方法,這時,如果想換一種方式實現(xiàn)數(shù)據(jù)訪問層,那么就必須修改業(yè)務(wù)邏輯層所有相關(guān)代碼。不利于程序的測試、維護以及進一步擴展。
針對上述傳統(tǒng)三層體系結(jié)構(gòu)出現(xiàn)的問題,以及系統(tǒng)中許多應(yīng)用都是由兩個或更多的類通過彼此合作來實現(xiàn)業(yè)務(wù)邏輯,這使得每個對象都需要與和它合作的對象的引用,如果這個獲取過程要靠自身實現(xiàn),那么將導(dǎo)致代碼高度耦合且難以測試。此時,引入了面向接口編程思想,使上層類不能具體依賴于下層類,而只依賴于下層提供的一個接口。為此,需要在傳統(tǒng)三層結(jié)構(gòu)的基礎(chǔ)上,再添加三個邏輯層,分別是接口層、接口實現(xiàn)層以及工廠層。改進后的多層體系結(jié)構(gòu)如圖2所示。
圖2 多層體系結(jié)構(gòu)圖
其中,業(yè)務(wù)邏輯層不再僅依賴于某一具體數(shù)據(jù)訪問層,而是利用.NET中的依賴注入機制以及創(chuàng)建工廠類的方式來動態(tài)加載實現(xiàn)。下面給出各層的引用關(guān)系及功能介紹。
1)WEB表示層:該層基本保持不變,與業(yè)務(wù)邏輯層之間采用緊耦合。另外,需要在該層中的Web.config文件的
2)BLL業(yè)務(wù)邏輯層:該層將不再直接引用數(shù)據(jù)訪問層,而是引用IDAL接口層和Factory工廠層。通過工廠層得到程序集指定類的實例并決定調(diào)用哪個數(shù)據(jù)訪問層的數(shù)據(jù)操作方法。
3)IDAL接口層:該層的設(shè)置目的是使業(yè)務(wù)邏輯與接口實現(xiàn)層(數(shù)據(jù)訪問層)的完全分離,一般僅需引用實體層。該層與具體的數(shù)據(jù)訪問層無關(guān),主要定義了數(shù)據(jù)訪問層必須要實現(xiàn)的業(yè)務(wù)邏輯操作集。即是規(guī)定系統(tǒng)必須要實現(xiàn)的所有業(yè)務(wù)功能。
4)Factory工廠層:該層引用接口層,主要是完成創(chuàng)建并返回所有的程序集實例。通過讀取web.config里設(shè)置的程序集名稱,加載類的實例,返回給BLL業(yè)務(wù)邏輯層使用。
5) SQLServerDAL接口實現(xiàn)層:又稱 SQL Server數(shù)據(jù)訪問層。引用 Model和IDAL,且繼承IDAL中的接口,主要是實現(xiàn)接口層IDAL中定義的方法。為了支持更多數(shù)據(jù)庫還可以有OracleDAL、AccessDAL的實現(xiàn),具體使用哪個由Factory工廠層決定。
6)DBUtility數(shù)據(jù)庫操作層:該層無需引用其它層。它是對ADO.NET數(shù)據(jù)訪問封裝的一個組件類庫,類庫中可以包括多個數(shù)據(jù)庫的訪問類,如SQLServerHelper、OracleHelper等,一般是為上層的具體某一數(shù)據(jù)訪問層提供通用的數(shù)據(jù)庫操作方法。
7) Entity實體層:該層無需引用其它層。主要擔(dān)負著數(shù)據(jù)在軟件架構(gòu)各層次及模塊間傳遞的職責(zé)。自始至終貫穿于整個軟件框架各層,它是現(xiàn)實生活中實體特性在計算機中的表示,其基本映射策略是每個實體類對應(yīng)一個數(shù)據(jù)庫表,且類成員往往與該數(shù)據(jù)表的表結(jié)構(gòu)一致[5]。
基于ASP.NET三層架構(gòu)的軟件開發(fā)已經(jīng)成為一種流行的開發(fā)模式,然而,傳統(tǒng)的三層架構(gòu)系統(tǒng)各層次之間存在緊耦合問題,針對這一問題,論文提出了一種面向接口編程思想應(yīng)用于三層架構(gòu)當(dāng)中,充分利用.NET中的依賴注入機制以及創(chuàng)建工廠類的方式來動態(tài)加載實現(xiàn)。實踐證明,應(yīng)用接口的多層架構(gòu)的開發(fā)模式不僅可以降低層次間的依賴關(guān)系,有利于標準化和開發(fā)人員工作的分配。還使得程序的靈活性更高,有利于各層邏輯的復(fù)用以及軟件后期維護和擴展。
[1]宋磊.基于ASP.NET的三層結(jié)構(gòu)實現(xiàn)方法研究[J].黑龍江科技信息,2010(15).
[2]徐楓.ASP.NET三層架構(gòu)體系分析與應(yīng)用[J].數(shù)據(jù)技術(shù)與應(yīng)用,2011(8):109-110.
[3]華銓平.抽象工廠設(shè)計模式在三層結(jié)構(gòu)開發(fā)中的應(yīng)用[J].大慶石油學(xué)院學(xué)報,2009,3(33).
[4]劉軍華,張麗敏.基于數(shù)據(jù)字典的實體類的設(shè)計與實現(xiàn)[J].湖南工業(yè)職業(yè)技術(shù)學(xué)院學(xué)報,2012(5).