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