實(shí)戰(zhàn)揭秘:開發(fā).Net平臺(tái)應(yīng)用系統(tǒng)框架
作者:孫亞民
本文選自:賽迪網(wǎng)
微軟的.Net平臺(tái)給應(yīng)用程序開發(fā)提供了一個(gè)非常好的基礎(chǔ)系統(tǒng)平臺(tái),,但是,如何在這個(gè)系統(tǒng)平臺(tái)上構(gòu)建 自己的應(yīng)用系統(tǒng),,還需要我們針對(duì)應(yīng)用系統(tǒng)的特點(diǎn),,構(gòu)建自己的應(yīng)用系統(tǒng)框架(Framework)。我們?cè)趹?yīng)用.Net開發(fā)系統(tǒng)的過程中,結(jié)合多年的開發(fā)經(jīng) 驗(yàn),,也參考了J2EE的架構(gòu),,設(shè)計(jì)了一套.Net下的應(yīng)用系統(tǒng)框架,以及相應(yīng)的中間件和開發(fā)工具,,已經(jīng)在多個(gè)項(xiàng)目中和軟件產(chǎn)品中應(yīng)用,,取得了很好的效果。 現(xiàn)在向代價(jià)介紹這個(gè)框架的整體解決方案,,希望對(duì)您有所幫助,。
我們知道,對(duì)于典型的三層應(yīng)用系統(tǒng)來說,,通??梢园严到y(tǒng)分成以下三個(gè)層次:
· 數(shù)據(jù)庫層
· 用戶界面層
· 應(yīng)用服務(wù)層
對(duì)于應(yīng)用系統(tǒng)來說,在這三個(gè)層次中,,系統(tǒng)的主要功能和業(yè)務(wù)邏輯在應(yīng)用服務(wù)層進(jìn)行處理,,對(duì)于系統(tǒng)框架來說,主要處理的也是這個(gè)層次的架構(gòu),。
對(duì)于應(yīng)用服務(wù)層來說,,在一個(gè)面向?qū)ο蟮南到y(tǒng)中,以下幾個(gè)方面的問題是必須要處理的:
· 數(shù)據(jù)的表示方式,,也就是實(shí)體類的表示方式,,以及同數(shù)據(jù)庫的對(duì)應(yīng)關(guān)系,即所謂的O-R Map的問題,。
· 數(shù)據(jù)的存取方式,,也就是實(shí)體類的持久化問題,通常采用數(shù)據(jù)庫來永久存儲(chǔ)數(shù)據(jù)實(shí)體,,這就需要解決同數(shù)據(jù)庫的交互問題,。這個(gè)部分要完成的功能,就是將數(shù)據(jù)實(shí)體
保存到數(shù)據(jù)庫中,,或者從數(shù)據(jù)庫中讀取數(shù)據(jù)實(shí)體,。同這個(gè)部分相關(guān)的,就是對(duì)數(shù)據(jù)訪問對(duì)象的使用,。在框架中,,我們對(duì)ADO.Net又做了一層封裝,使其使用更
加簡(jiǎn)便,,同時(shí)也統(tǒng)一了對(duì)ADO.Net的使用方式,。
· 業(yè)務(wù)邏輯的組織方式。在面向?qū)ο蟮南到y(tǒng)中,,業(yè)務(wù)邏輯是通過對(duì)象間的消息傳遞來實(shí)現(xiàn)的,。在這個(gè)部分,,為了保證邏輯處理的正確性和可靠性,還必須支持事務(wù)處理的能力,。
· 業(yè)務(wù)服務(wù)的提供方式,。為了保證系統(tǒng)的靈活性和封裝性,系統(tǒng)必須有一個(gè)層來封裝這些業(yè)務(wù)邏輯,,向客戶端提供服務(wù),,同時(shí)作為系統(tǒng)各個(gè)模塊間功能調(diào)用的接口,保
證系統(tǒng)的高內(nèi)聚和低耦合性,。這里的客戶指的不是操作的用戶,,而是調(diào)用的界面、其他程序等,。Web層(ASP.Net頁面)通常只同這個(gè)部分交互,,而不是直 接調(diào)用業(yè)務(wù)邏輯層或者數(shù)據(jù)實(shí)體的功能。
為了能夠很好的解決這些問題,,我們?cè)O(shè)計(jì)了這個(gè)框架,。在框架中,針對(duì)以上問題,,我們將應(yīng)用服務(wù)層又劃分成五個(gè)層次:數(shù)據(jù)實(shí)體層,、實(shí)體控制層、數(shù)據(jù)訪問層,、業(yè)務(wù)規(guī)則層和業(yè)務(wù)外觀層,。各個(gè)層次同上述問題的關(guān)系可以用表表示如下:
層次 問題
數(shù)據(jù)實(shí)體層 數(shù)據(jù)的表示方式
實(shí)體控制層 數(shù)據(jù)的存取方式
數(shù)據(jù)訪問層 提供對(duì)數(shù)據(jù)庫的訪問,封裝ADO.Net
業(yè)務(wù)規(guī)則層 業(yè)務(wù)邏輯的組織方式
業(yè)務(wù)外觀層 業(yè)務(wù)服務(wù)的提供方式
整個(gè)系統(tǒng)的結(jié)構(gòu)圖如下:
圖中的箭頭表示使用關(guān)系
將系統(tǒng)劃分成這么多層次,,其好處是能夠使得系統(tǒng)的架構(gòu)更加清晰,,這樣每個(gè)層次完成的功能就比較單一,功能的代碼有規(guī)律可循,,也就意味著我們可以開發(fā)一些工
具來生成這些代碼,,從而減少代碼編寫的工作量,使得開發(fā)人員可以將更多的精力放到業(yè)務(wù)邏輯的處理上,。正是基于這個(gè)想法,,我們同時(shí)開發(fā)了針對(duì)這個(gè)框架的開發(fā)
工具,并在實(shí)際工作中減少很多代碼的編寫量,,效果非常好,。同時(shí),為了應(yīng)用服務(wù)層更好的工作,,我們?cè)O(shè)計(jì)了一個(gè)支持這個(gè)框架的應(yīng)用系統(tǒng)中間件,。(現(xiàn)在,已經(jīng)有
多家其他公司在試用這個(gè)中間件系統(tǒng),。)
同J2EE的EntityBean不同的是,,我們采用了數(shù)據(jù)實(shí)體和實(shí)體控制分開的設(shè)計(jì)方法,這樣的做法會(huì)帶來一定的好處,。
下面我將各個(gè)部分的設(shè)計(jì)方案和策略詳細(xì)介紹如下:
數(shù)據(jù)實(shí)體層
我們首先需要解決的是數(shù)據(jù)的表示方式的問題,,也就是通常的O-R Map的問題。
O-R Map通常的做法是將程序中的類映射到數(shù)據(jù)庫的一個(gè)或多個(gè)表,,例如一個(gè)簡(jiǎn)單的Product類:
public class Product
{
string ProductID;
string ProductName;
float Account;
}
在數(shù)據(jù)庫中可能對(duì)應(yīng)了一張Product表:
字段名 數(shù)據(jù)類型
ProductID Varchar(40)
ProductName Varchar(50)
Account float
這是最通常的做法,,但是,由這種方式會(huì)帶來一些問題,。首先就是數(shù)據(jù)實(shí)體在數(shù)據(jù)庫和程序中的表現(xiàn)方式不一樣,,對(duì)于一些涉及到多個(gè)表的“粗粒度對(duì)象”,一個(gè)實(shí) 體類可能會(huì)引用到多個(gè)其它實(shí)體類,,也就是說會(huì)在涉及到對(duì)象粒度的建模方面帶來一些問題,;其次在同數(shù)據(jù)庫交互時(shí),也涉及到一個(gè)轉(zhuǎn)換的問題,,如果一個(gè)對(duì)象涉及
到對(duì)多個(gè)表的操作,,問題就更大;最后,,當(dāng)系統(tǒng)做查詢操作,,需要返回多個(gè)對(duì)象時(shí),因?yàn)樯婕暗睫D(zhuǎn)換的問題,,效率就比較低下,,而如果采用直接返回?cái)?shù)據(jù)集的方式,
雖然能夠提高效率,,又會(huì)帶來數(shù)據(jù)表達(dá)方式不一致的問題,。
考慮到上述問題,我們?cè)跀?shù)據(jù)實(shí)體的表現(xiàn)上采用了另外一種方式,,那就
是利用DataSet,。DataSet是微軟在ADO.Net中新提出的數(shù)據(jù)對(duì)象,同ADO的Recordset不同的是,,他能夠容納多個(gè)記錄集,。 DataSet類似于一個(gè)內(nèi)存數(shù)據(jù)庫,由多個(gè)DataTable組成,,而一個(gè)DataTable又有多個(gè)Column,。這樣的結(jié)構(gòu),使得他可以同數(shù)據(jù)庫很 好的進(jìn)行映射,。同時(shí),,我們吸取了J2EE架構(gòu)中CMP使用XML文件定義實(shí)體類結(jié)構(gòu)的優(yōu)點(diǎn),采用了類似的解決方案,。
因此,,在這個(gè)方面我們是這樣來進(jìn)行處理的:
1) 核心類庫定義了EntityData類,,這個(gè)類繼承了DataSet,添加了一些方法,,用來作為所有實(shí)體類的框架類,,定義了各個(gè)實(shí)體類的一般結(jié)構(gòu),至于每個(gè)實(shí)體類具體的結(jié)構(gòu),,在運(yùn)行時(shí)刻由下述辦法確定:
2) 實(shí)體類的定義通過XML文件來確定,,該XML文件符合JIXML對(duì)象實(shí)體描述語言的規(guī)范(注:JIXML是我們開發(fā)的 對(duì)象-實(shí)體 映射語言),用于確定實(shí)體類的結(jié)構(gòu),。例如,,一個(gè)關(guān)于訂單的實(shí)體類的定義可能類似于下面的結(jié)構(gòu):
3) 實(shí)體對(duì)象的結(jié)構(gòu)由一系列的類構(gòu)造器在運(yùn)行時(shí)刻,根據(jù)上述規(guī)范制定的XML來生成,。這些類構(gòu)造器實(shí)現(xiàn)IClassBuilder接口,。我們?cè)谙到y(tǒng)核心類庫中預(yù)定義了一些標(biāo)準(zhǔn)的Builder,一般情況下,,直接使用這些標(biāo)準(zhǔn)的Builder就可以了,。
類構(gòu)造器采用的類構(gòu)造工廠的設(shè)計(jì)模式,如果使用者覺得標(biāo)準(zhǔn)的Builder不能滿足要求,,也可以擴(kuò)展IClassBuilder接口,,編寫自己的類構(gòu)造器,然后在系統(tǒng)配置文件中指明某各類的類構(gòu)造器的名稱即可,。
IClassBuilder的定義如下:
public interface IClassBuilder
{
EntityData BuildClass(string strClassName); //獲取類數(shù)據(jù)結(jié)構(gòu)
SqlStruct GetSqlStruct(string strClassName,string strSqlName);
}
這個(gè)部分的結(jié)構(gòu)可以用類圖表示如下:
當(dāng)使用者需要某個(gè)實(shí)體類的時(shí)候,,只要采用如下語句:
EntityData
entity=EntityDataManager.GetEmptyEntity("Product");
EntityDataManager的GetEmptyEntity方法通過調(diào)用ClassBuilder的BuildClass來實(shí)現(xiàn),并且實(shí)現(xiàn)對(duì)象的緩存功能,。
ClassBuilder的BuildClass方法實(shí)現(xiàn)如下:
public EntityData BuildClass(string strClassName)
{
IClassBuilder
builder=ClassBuilderFactory.GetClassBuilder(strClassName);
return builder.BuildClass(strClassName);
}
這兒綜合使用了Builder和Factory的設(shè)計(jì)模式,。ClassBuilderFactory的作用是根據(jù)實(shí)體類的名稱,讀取配置文件中相應(yīng)的類構(gòu)造器的具體類名,,并返回具體的類構(gòu)造器,。
配置文件ClassBuilders.xml的結(jié)構(gòu)很簡(jiǎn)單:
<?xml version="1.0" encoding="gb2312" ?>
<Builders>
<Class Name="ProductType"
BuilderName="Jobsinfo.SingleTableClassBuilder" />
</Builders>
如果沒有為某個(gè)實(shí)體類指明具體的Builder,系統(tǒng)將調(diào)用默認(rèn)的Builder來構(gòu)造實(shí)體對(duì)象的結(jié)構(gòu),。
系統(tǒng)同時(shí)提供了實(shí)體對(duì)象緩存服務(wù),。通過上述方式產(chǎn)生的實(shí)體對(duì)象可以被緩存,這樣,,在第二次調(diào)用該對(duì)象時(shí),,可以從緩存中讀取,而不用從頭重新生成,,從而大大提高了系統(tǒng)的性能,。
在實(shí)際的開發(fā)過程中,我們感覺到,,數(shù)據(jù)實(shí)體層采用這種設(shè)計(jì)模式具有以下優(yōu)點(diǎn):
· 實(shí)體類定義XML文件可以通過工具來自動(dòng)生成,,減輕開發(fā)工作量,。
· 在執(zhí)行查詢操作時(shí),不論是返回一個(gè)實(shí)體,,還是多個(gè)實(shí)體,,數(shù)據(jù)的表現(xiàn)方式都一樣,,都是EntityData,,而不存在如上面所述的單個(gè)對(duì)象和數(shù)據(jù)集的表現(xiàn)方式不統(tǒng)一的問題。
· 在修改實(shí)體類的定義時(shí),,如果修改的部分不涉及到業(yè)務(wù)邏輯的處理,,只需要修改XML文件就可以了,不用修改其它程序和重新編譯,。
· 系統(tǒng)提供的實(shí)體對(duì)象緩存服務(wù)可以大大提高了系統(tǒng)的性能,。
· 類構(gòu)造工廠的設(shè)計(jì)模式大大提高了系統(tǒng)的靈活性。
實(shí)體控制層
解決和O-R Map的問題,,需要考慮的就是實(shí)體類的持久性問題了,,也就是同數(shù)據(jù)庫的交互問題。實(shí)體控制層用于控制數(shù)據(jù)的基本操作,,如增加,、修改、刪除,、查詢等,,同時(shí)為業(yè)務(wù)規(guī)則層提供數(shù)據(jù)服務(wù)。
實(shí)體控制層的類實(shí)現(xiàn)IEntityDAO接口,。這個(gè)接口定義了實(shí)現(xiàn)數(shù)據(jù)操縱的主要必要方法,,包括增加、修改,、刪除和查找,。IEntityDAO的定義如下:
public interface IEntityDAO : IDisposable
{
void InsertEntity(EntityData entity);
void UpdateEntity(EntityData entity);
void DeleteEntity(EntityData entity);
EntityData FindByPrimaryKey(object strKeyValue);
}
可以看到,這個(gè)接口同J2EE中EntityBean的接口定義很象,,實(shí)際上,,我們也是參考了EntityBean的解決方案。
下面是一個(gè)Product的DAO類的例子:
public class ProductEntityDAO: IEntityDAO
{
private DBCommon db; //這是數(shù)據(jù)庫訪問的類
public ProductEntityDAO()
{
db=new DBCommon();
db.Open();
}
public ProductEntityDAO(DBCommon cdb)
{
this.db=cdb;
}
// 插入一個(gè)實(shí)體
public void InsertEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
db.exeSql(row,SqlManager.GetSqlStruct("Product","InsertProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}
//修改一個(gè)實(shí)體類
public void UpdateEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
if(row.RowState!=DataRowState.Unchanged)
db.exeSql(row,SqlManager.GetSqlStruct("Product","UpdateProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}
//刪除一個(gè)實(shí)體類
public void DeleteEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
db.exeSql(row,SqlManager.GetSqlStruct("Product","DeleteProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}
//查找實(shí)體類
public EntityData FindByPrimaryKey(object KeyValue)
{
EntityData entity=new EntityData("Product");
SqlStruct
sqlProduct=SqlManager.GetSqlStruct("Product","SelectByIDProduct");
db.FillEntity(sqlProduct.SqlString,sqlProduct.ParamsList[0],
KeyValue,entity,"Product");
return entity;
}
public EntityData FindAllProduct()
{
EntityData entity=new EntityData("Product");
SqlStruct
sqlProduct=SqlManager.GetSqlStruct("Product","FindAllProduct");
db.FillEntity(sqlProduct.SqlString,null,null,entity,"Product");
return entity;
}
// 校驗(yàn)數(shù)據(jù)數(shù)據(jù)輸入的有效性
private void CheckData(EntityData entity)
{
if(entity.Tables["Product"].Rows[0]["ProductID"].ToString().Length>40)
throw new ErrorClassPropertyException
("Property ProductID should be less than 40 characters");
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
protected virtual void Dispose(bool disposing)
{
if (! disposing)
return; // we‘re being collected,
so let theGC take care of this object
db.Close();
}
}
同數(shù)據(jù)實(shí)體層相結(jié)合,,這兩部分實(shí)現(xiàn)了應(yīng)用服務(wù)層同數(shù)據(jù)庫的交互,。這兩個(gè)部分結(jié)合,完成了類似于J2EE中EntityBean的功能,。
采用數(shù)據(jù)實(shí)體和實(shí)體控制分開的設(shè)計(jì)方法,,具有以下優(yōu)點(diǎn):
· 避免了J2EE體系中操縱EntityBean系統(tǒng)資源消耗大,效率低下的缺陷,。
· 解決了J2EE體系中使用EntityBean傳輸數(shù)據(jù)時(shí)開銷大,,過程復(fù)雜,、效率低的缺陷。
· 可以單獨(dú)修改實(shí)體結(jié)構(gòu)和對(duì)實(shí)體數(shù)據(jù)的操縱,,使得系統(tǒng)更加靈活
· 數(shù)據(jù)實(shí)體的XML定義文件和實(shí)體控制層的類可以通過工具自動(dòng)生成,,減輕開發(fā)工作量。
數(shù)據(jù)訪問層
為了為實(shí)體控制層提供對(duì)數(shù)據(jù)庫操作的服務(wù),,我們?cè)O(shè)計(jì)了這個(gè)部分,。這個(gè)層次通常執(zhí)行以下一些操作:
· 連接數(shù)據(jù)庫
· 執(zhí)行數(shù)據(jù)庫操作
· 查詢數(shù)據(jù)庫,返回結(jié)果
· 維護(hù)數(shù)據(jù)庫連接緩存
· 數(shù)據(jù)庫事務(wù)調(diào)用
為了統(tǒng)一對(duì)數(shù)據(jù)的訪問方式,,我們?cè)谠O(shè)計(jì)的時(shí)候,,在框架的類庫中包含了數(shù)據(jù)訪問服務(wù),封裝了常用的對(duì)各種數(shù)據(jù)庫的操作,,可以訪問不同類型的數(shù)據(jù)庫,,這樣,在
具體軟件系統(tǒng)開發(fā)的時(shí)候,,可以不用考慮同數(shù)據(jù)庫的連接等問題,,也使得應(yīng)用系統(tǒng)在更換數(shù)據(jù)庫時(shí),不用修改原有的代碼,,大大簡(jiǎn)化了開發(fā)和部署工作,。數(shù)據(jù)訪問服
務(wù)還維護(hù)數(shù)據(jù)庫連接緩存,提高系統(tǒng)性能,,以及對(duì)數(shù)據(jù)庫事務(wù)調(diào)用的服務(wù),。
數(shù)據(jù)訪問服務(wù)在核心類庫中主要通過DBCommon類來提供對(duì)數(shù)據(jù)訪問功能調(diào)用的服務(wù)。DBCommon的使用方法在上面的ProductEntityDAO中可以看出一二,。更多的可以看看Demo工程中的使用,。
業(yè)務(wù)規(guī)則層
業(yè)務(wù)規(guī)則層需要完成的功能是各種業(yè)務(wù)規(guī)則和邏輯的實(shí)現(xiàn)。業(yè)務(wù)規(guī)則完成如客戶帳戶和書籍訂單的驗(yàn)證這樣的任務(wù),。這是整個(gè)應(yīng)用系統(tǒng)中最為復(fù)雜的部分,,沒有太多
的規(guī)律可循。但是,,我們?cè)谕瓿缮厦娴墓ぷ骱?,?duì)于這個(gè)部分的開發(fā),也可以起到一定的簡(jiǎn)化的工作,。這從下面的例子可以看到,。
業(yè)務(wù)規(guī)則層的設(shè)計(jì)通常需要進(jìn)行很好的建模工作。業(yè)務(wù)規(guī)則的建模,,一般采用UML來進(jìn)行,。可以使用UML的序列圖、狀態(tài)圖,、活動(dòng)圖等來為業(yè)務(wù)規(guī)則建模,。這個(gè)部分的工作,通常通過一系列的類之間的交互來完成,。
業(yè)務(wù)規(guī)則通常要求系統(tǒng)能夠支持事務(wù)處理(Transaction),。在這個(gè)地方,.Net提供了很方便的調(diào)用Windows
Transaction Server的手段,。關(guān)于這個(gè)部分的內(nèi)容,,各位自己閱讀MSDN就非常清楚了,這里就不做詳細(xì)的介紹了,。 虛擬主機(jī)
例如,,在一個(gè)庫存系統(tǒng)的入庫單入庫操作中,,除了需要保存入庫單外,,在這個(gè)之前,還必須對(duì)入庫單涉及的產(chǎn)品的數(shù)量進(jìn)行修改,,其代碼通常如下(使用了事務(wù)處理):
public void StoreIntoWarehouse(EntityData IndepotForm)
{
DataTable tbl=IndepotForm.Tables["InDepotFormDetail"];
try
{
ProductEntityDAO ped=new ProductEntityDAO();
for(int i=0;i<tbl.Rows.Count;i++)
{
DataRow formdetail=tbl.Rows[i];
string productID=formdetail["ProductID"].ToString();
decimal
inCount=(decimal)formdetail["InCount"];
EntityData product=ped.FindByPrimaryKey(productID);
DataRow productRow=product.GetRecord("Product");
productRow["CurrentCount"]=(decimal)productRow["CurrentCount"]+inCount;
ped.UpdateEntity(product);
}
ped.Dispose();
InDepotFormEntityDAO inDepotForm=new
InDepotFormEntityDAO();
inDepotForm.InsertEntity(IndepotForm);
IndepotForm.Dispose();
ContextUtil.SetComplete();
}
catch(Exception ee)
{
ContextUtil.SetAbort();
throw ee;
}
}
業(yè)務(wù)外觀層
業(yè)務(wù)外觀層為 Web 層提供處理,、瀏覽和操作的界面。業(yè)務(wù)外觀層用作隔離層,,它將用戶界面與各種業(yè)務(wù)功能的實(shí)現(xiàn)隔離開來,。 虛擬主機(jī)
業(yè)務(wù)外觀層只是將已經(jīng)完成的系統(tǒng)功能,根據(jù)各個(gè)模塊的需要,,對(duì)業(yè)務(wù)規(guī)則進(jìn)行高層次的封裝,。
框架沒有規(guī)定采用在業(yè)務(wù)外觀層采用何種實(shí)現(xiàn)方式,但是建議使用Web Service來提供服務(wù),。采用IIS為Web服務(wù)器,,可以很方便的部署Web Service。
· Web層
Web 層為客戶端提供對(duì)應(yīng)用程序的訪問,。Web 層由 ASP.NET Web
窗體和代碼隱藏文件組成,。Web
窗體只是用 HTML 提供用戶操作,而代碼隱藏文件實(shí)現(xiàn)各種控件的事件處理,。
通常,,對(duì)于數(shù)據(jù)維護(hù)類型的ASP.NET
Web 窗體和控件事件處理代碼,我們提供了工具來生成,,減輕開發(fā)工作量,。
除了上述6個(gè)邏輯層以外,系統(tǒng)通常還包括一個(gè)系統(tǒng)配置項(xiàng)目,,提供應(yīng)用程序配置和跟蹤類,。
框架服務(wù)的設(shè)計(jì)策略
為了能夠很好的支持上面所述的系統(tǒng)架構(gòu),我們需要一套核心的類庫,以實(shí)現(xiàn)對(duì)構(gòu)筑其上的應(yīng)用軟件的支持,。這樣,,在具體每個(gè)應(yīng)用系統(tǒng)的開發(fā)時(shí),可以省略很多基礎(chǔ)性的工作,,提高開發(fā)的效率,。在這個(gè)方面,我們?cè)O(shè)計(jì)了以下核心類和接口:
· EntityData:定義實(shí)體類的通用結(jié)構(gòu)
· IClassBuilder:定義實(shí)體類結(jié)構(gòu)構(gòu)造的結(jié)構(gòu),。我們預(yù)定義了根據(jù)這個(gè)接口實(shí)現(xiàn)的幾個(gè)標(biāo)準(zhǔn)類:AbstractClassBuilder,、 SingletableClassBuilder、ThickClassBuilder,、StandardClassBuilder,。這些Builder 通過ClassBuilderFactory進(jìn)行管理。
· IEntityDAO:定義實(shí)體控制類的接口
· EntityDataManager:提供對(duì)所有實(shí)體類的緩存管理和查找服務(wù)
· DBCommon:封裝數(shù)據(jù)庫操作
· ApplicationConfiguration:記錄系統(tǒng)配置
· SqlManager:管理系統(tǒng)的SQL語句及其參數(shù),。
通過這些核心的類和接口,,框架能夠?yàn)閼?yīng)用系統(tǒng)提供如下服務(wù):
· O-R Map:對(duì)象-關(guān)系數(shù)據(jù)庫映射服務(wù)
這部分完成應(yīng)用程序中的實(shí)體對(duì)象同關(guān)系型數(shù)據(jù)庫的映射,主要為數(shù)據(jù)實(shí)體層提供服務(wù),。
在這個(gè)部分中,,定義了JIXML實(shí)體-對(duì)象映射語言。這是我們開發(fā)的一種使用XML來描述對(duì)象-實(shí)體間的映射關(guān)系的規(guī)范語言,,開發(fā)者可以使用它來描述對(duì)象 -實(shí)體間的映射關(guān)系,。開發(fā)者也可以直接擴(kuò)展IClassBuilder接口,手工完成對(duì)象-實(shí)體間映射關(guān)系的代碼,。系統(tǒng)在運(yùn)行時(shí)刻,,會(huì)根據(jù)配置文件的設(shè) 置,調(diào)用實(shí)體類的構(gòu)造器,,動(dòng)態(tài)構(gòu)造出實(shí)體對(duì)象的結(jié)構(gòu),。虛擬主機(jī)
· Database Access:數(shù)據(jù)庫訪問服務(wù)
這個(gè)部分提供對(duì)數(shù)據(jù)庫訪問的服務(wù)。在這個(gè)框架上構(gòu)建的應(yīng)用軟件系統(tǒng),,不直接操縱數(shù)據(jù)庫,,而是通過類庫提供的數(shù)據(jù)訪問服務(wù)來進(jìn)行。數(shù)據(jù)庫訪問服務(wù)作為應(yīng)用程序同數(shù)據(jù)庫之間的中介者,,能夠有效防止對(duì)數(shù)據(jù)庫的不安全操作,。
數(shù)據(jù)庫訪問服務(wù)同時(shí)提供了對(duì)數(shù)據(jù)庫庫事務(wù)處理的調(diào)用方法,開發(fā)者可以很方便的通過數(shù)據(jù)庫訪問服務(wù)調(diào)用數(shù)據(jù)庫的事務(wù)處理功能,。
· DML Search:數(shù)據(jù)操縱語句查詢服務(wù)
在系統(tǒng)架構(gòu)中,,對(duì)數(shù)據(jù)庫進(jìn)行操作的SQL語句不在程序中硬編碼,而是同數(shù)據(jù)實(shí)體層的實(shí)體類結(jié)構(gòu)一樣在XML文件中描述,,其結(jié)構(gòu)符合JIXML規(guī)范,。這些操 縱語句中的基本部分,,如數(shù)據(jù)的插入、刪除,、修改,、查詢等語句,可以通過我們自己開發(fā)的工具生成,。這樣,,在系統(tǒng)的便于修改性和靈活性上能夠得到很大的提高。
這樣一來,,系統(tǒng)必須提供這些數(shù)據(jù)操縱語句的查詢服務(wù),。核心類庫提供了在XML文件中查找這些數(shù)據(jù)操縱語句和相關(guān)參數(shù)的服務(wù)。
· Entity Buffer&Search:實(shí)體對(duì)象緩存&查找服務(wù)
系統(tǒng)中的實(shí)體對(duì)象在第一次創(chuàng)建后,,就被系統(tǒng)緩存起來,,當(dāng)系統(tǒng)第二次需要訪問該對(duì)象時(shí),不需要再從頭創(chuàng)建這個(gè)對(duì)象,,而只需要從緩存中取出即可,。這就是框架提
供的實(shí)體對(duì)象緩存服務(wù)。同這個(gè)服務(wù)相關(guān)聯(lián)的是實(shí)體對(duì)象的查找服務(wù),,即從這些緩存的實(shí)體對(duì)象中尋找相應(yīng)的實(shí)體對(duì)象的服務(wù),。
· Transaction:事務(wù)處理服務(wù)
我們充分利用Windows
COM+事務(wù)處理機(jī)制的強(qiáng)大功能,使在應(yīng)用程序能夠充分使用事務(wù)處理的功能,,保證應(yīng)用系統(tǒng)的穩(wěn)定性和可靠性。
當(dāng)某個(gè)類需要使用事務(wù)處理功能時(shí),,首先使該類繼承System.EnterpriseServices名稱空間下的ServicedComponent 類,,然后使用如下方式申明該類使用的事務(wù)類型:[Transaction(TransactionOption.Required)]。系統(tǒng)在該類第一次 被調(diào)用時(shí),,自動(dòng)在COM+服務(wù)中注冊(cè)中該類,,使得應(yīng)用程序可以使用COM+的事務(wù)處理功能。
系統(tǒng)支持如下幾種事務(wù)處理類型:
成員名稱 說明
Disabled 忽略當(dāng)前上下文中的任何事務(wù),。
NotSupported 使用非受控事務(wù)在上下文中創(chuàng)建組件,。
Required 如果事務(wù)存在則共享事務(wù),并且如有必要?jiǎng)t創(chuàng)建新事務(wù),。
RequiresNew 使用新事務(wù)創(chuàng)建組件,,而與當(dāng)前上下文的狀態(tài)無關(guān)。
Supported 如果事務(wù)存在,,則共享該事務(wù),。
同時(shí),為了簡(jiǎn)化開發(fā),,我們還為這個(gè)框架設(shè)計(jì)了一個(gè)開發(fā)工具,,并且作為插件集成到VS.Net的開發(fā)環(huán)境中,能夠大大減少開發(fā)的代碼編寫工作量。
這樣,,通過以上這些工作,,我們達(dá)到了以下目標(biāo):
· 有了一個(gè)非常清晰的系統(tǒng)架構(gòu) 虛擬主機(jī)
· 因?yàn)橛辛艘惶缀诵牡念悗靵頌閼?yīng)用系統(tǒng)提供服務(wù),使得我們?cè)诤竺娴拈_發(fā)過程中可以減少很多基礎(chǔ)性的工作
· 有了自己的有針對(duì)性的開發(fā)工具,,能夠減少大量的重復(fù)編碼的工作,。
為了讀者能夠更好的了解系統(tǒng)的結(jié)構(gòu),附上一個(gè)Demo工程(下載Demo工程),。這是一個(gè)簡(jiǎn)單的倉庫入庫的示例,,基本上展示了這個(gè)框架的應(yīng)用系統(tǒng)的結(jié)構(gòu)和核心類庫的使用。
不得不看得實(shí)戰(zhàn)內(nèi)容:利用.Net框架開發(fā)應(yīng)用系統(tǒng)
作者簡(jiǎn)介:孫亞民,,1998年畢業(yè)于南京大學(xué),,現(xiàn)任蘇州迪訊軟件開發(fā)有限公司技術(shù)總監(jiān),熟悉J2EE架構(gòu),、.Net以及C#語言,。
|