delphi三層框架設計
大多數文章中都或多或少的講到了三層架構。表示層,業務層,數據層。又把業務層再細分,分爲外觀服務層,主業務服務,及數據庫庫服務層。
今天主要討論一下業務層吧。舉個最簡單的例子。客戶端獲取數據。
業務層要與表示層儘量解藕, 我的方法是:首先我們在中間層TLB_中定義一個接口 IBusinessService, 定義一個方法。getvoList,我要得到一個VO的列表, VO即ValueObject, 例如:
TValueObject= class(TPersistent)
private
b_insertFlag :Boolean;
b_updateFlag :Boolean;
b_deleteFlag :Boolean;
d_rowVersion :double;
procedure setInsertFlag(pInsertFlag :Boolean);
function getInsertFlag: Boolean;
procedure setUpdateFlag(pUpdateFlag :Boolean);
function getUpdateFlag: Boolean;
procedure setDeleteFlag(pDeleteFlag :Boolean);
function getDeleteFlag: Boolean;
procedure setRowVersion(pRowVersion :double);
function getRowVersion:double;
protected
function GetOLEData: OleVariant; virtual;
procedure SetOLEData(const Value: OleVariant); virtual;
published
property bInsertFlag: Boolean read getInsertFlag write setInsertFlag;
property bUpdateFlag: Boolean read getUpdateFlag write setUpdateFlag;
property bDeleteFlag: Boolean read getDeleteFlag write setDeleteFlag;
property dRowVersion: double read getRowVersion write setRowVersion;
property POLEData:OleVariant read GetOLEData write SetOLEData;
end;
TUserVO = class(TValueObject)
private
id: string;
name: string;
password: string;
。。。。。。。。。。。。。。。
VO的列表:
TValueObjectList = Class(TObjectList)
private
ValueObject: TValueObject;
ClassName: TClass;
procedure setClassName(pTmpClsName :TClass);
function getClassName: TClass;
procedure setValueObject(pTmpVO :TValueObject);
function getValueObject: TValueObject;
protected
function GetOLEData: OleVariant; virtual;
procedure SetOLEData(const Value: OleVariant); virtual;
published
function AddItem(index: integer; AObject: TObject ):Integer; virtual;
function GetItem(index, itemid: integer ): TObject; virtual;
function CountItem:Integer; virtual;
public
constructor Create; virtual;
destructor Destroy; override;
procedure AfterConstruction; override;
property PClassName: TClass read getClassName write setClassName;
property POLEData: OleVariant read GetOLEData write SetOLEData;
property PValueObject: TValueObject read getValueObject write setValueObject;
end;
TValueObjectList就是VO的裝載器。在 JAVA中有一個好聽的叫法,
VOList值列表組裝器,具體的功能是可以管理VO, 當然你可以進行擴充,比如後來我加入了OLE<->TOBJECT<->TDataset互換的功能。
主鍵生成機制,分頁存取功能,生成子集功能,及懶裝載功能,壓縮傳輸流功能等,同步數據更新問題等。這要你自己去發揮吧。
說了這麼多,話題轉回來吧。現在說客戶端怎麼去存取數據。
在前面中間層已經定義了IBusinessService, 定義一個方法。getvoList,這個就是通用存取數據的接口了。
下面看看他的完整形式:
procedure getvoList(const sBOName: WideString; const sBOService: WideString;
out voListObj: OleVariant);
這裏有三個參數,sBOName:sBOService:voListObj:
幹什麼用的?第一個就是業務對象名稱, 第二個是業務對象服務名稱,第三個是傳回來的olevariant;
強調一點。sBOName:sBOService:這兩個參數並不直接對應中間層的業務對象。之間加了一個轉換層。也就是service定位層。這個東西把客戶傳來的兩個參數定位到相應的業務對象中。有什麼好處呢。其實就相當於客戶端和中間層的一個簡單的協議,客戶端發一個boname,一個服務名,這都是約定的。也就是不變的。以後該業務要變,就十分方便,只需要在中間層的定位器,配置一下就可以了,如果採用XML或文件配置,不需要修改任何程序,客戶的業務已經發生改變
當然會採用名字調用等技術了。相關代碼如下:
TBOService= class(TServiceObject)
private
//srvOBName : String;
IBasBO: IBaseBO;
BOPool: TBOPrototype; //業務對象持久池:
public
constructor Create;
procedure getvoList(const sBOName: WideString; const sBOService: WideString;
out voListObj: OleVariant); safecall;
。。。。。。。。。。。。。。。。。。。。。
再說說TBOPrototype吧 ,這個東西是管理業務對象池的。由他統一創建業務對象。採用的是單例模式。
之後具體的調用,相關代碼如下:
if FindClass(fClsPer.ClassName) <> nil then
begin
tmpPer := TPersistentClass(FindClass(fClsPer.ClassName)).Create;
Supports(tmpPer, StringToGUID('{3AE5EA91-41EA-41E7-B40C-CF00F8B75F8A}'), IBasBO);
try
IBasBO.InitBusinessObj;
voListObj := IBasBO.GetDAOValueObject.getDAOValueList;
finally
IBasBO := nil;
end;
end
else
ShowMessage('no found!');
其中IBasBO,是一個接口定義,
IBaseBO = interface(IUnknown)
['{3AE5EA91-41EA-41E7-B40C-CF00F8B75F8A}']
function GetObject: TObject;
procedure SetObject( value: TObject );
function GetDAOValueObject: TDAOValueObject;
procedure SetDAOValueObject(tmpDAOVO: TDAOValueObject);
procedure InitBusinessObj;
end;
呵呵,現在可以看到冰山一角了吧。
經過業務對象初始化之後,他就去創建DAO了。。。呵呵。 如果你不瞭解DAO,看看相關的資料吧。。。。。
主要功能就是把數據存儲隱藏起來,調用SQL, ORACLE,之類。我主要是用它調用數據庫工廠創建。
大致看一下代碼吧。
//--------------------------------------------------------------------------
//1.工廠基類(SQLServer工廠類)
//--------------------------------------------------------------------------
unit ConnDBFactory_SQLServer;
interface
uses
Classes, ADODB, ConnDB, DB, DBTables, Controls, Dialogs, IConnDB, ConnDBFactory;
type
TConnBDEDBFactory_SQLServer = class(TConnDBFactory)
public
function CreatorConnDB() :IConnDataBase; override;
end;
TConnADODBFactory_SQLServer = class(TConnDBFactory)
public
function CreatorConnDB() :IConnDataBase; override;
end;
又扯遠了,還是再回來吧。中間層的定位器通用業務對象管理器創建或獲得一個業務對象之後,定位到相應的服務上去。比如數據存取。這裏有一點說明:就是業務對象的數據存取和業務服務是分開的。 數據存取就採用DAO的方法。
直接一點說就是創建DAO對象。
這是 TDAOValueObject= class(TPersistent, IDAOValueObject)
private..
.............
上面的是基類。完成基礎服務的。看看接口吧。
IDAOValueObject = interface(IUnknown)
['{DF03C9E7-2A5B-4E32-8EF5-C4E8FC77E8BB}']
function createDAOValue: TValueObject;
function insertDAOValue(pValueObject: TValueObject): Integer;
function updateDAOValue(pValueObject: TValueObject) :Integer;
function deleteDAOValue(pValueObject: TValueObject) :Integer;
function findByPrimaryKey(const pServiceName: WideString; vKey: OleVariant): TValueObject;
function getDAOValueList: OleVariant; overload;
function getDAOValueList(sSQL: String): OleVariant; overload;
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
看看幹了什麼。。。。
inherited Create;
sqlAnySrvObj := TSQLAnalyzeService.Create;
if not assigned(VOList) then
VOList := TValueObjectList;
VOList.pVOClassName := ‘TUSERVO’
創建了一個SQL分析器。 一個VOLIST對象, 並且傳了一個VO名字。。
TSQLAnalyzeService,SQL分析器可以動態的生成SQL腳本。。
再看看
function getDAOValueList: OleVariant; overload;
function getDAOValueList(sSQL: String): OleVariant;
這兩個函式吧。 把生成的VO, olevariant化。
這些基礎的工作, 已經由VOLIST做了。
重要的一點:
prepareTable,這是VOLIST中的函式,由他動態的生成TDATASET, 當然沒必要在中間層生成。但可以打包傳給客戶端,就OK了。
現在在看一下客戶端的代碼吧:
MyInterface2.getvoList('TUserBO', '' , oo);
pp := TValueObjectList.Create;
pp.OLEToDS(oo);
dataSource1.DataSet := pp.pDataSet;
呵呵,PP是公共的TVOLIST,發佈到客戶端。 通由Ole,自動生成了TDATASET。
想用對象,沒問題,看下面:
定義: ss: TVALUEOBJECT;
ss := TUserVO(pp.GetItem(1));
if ss<>nil then
ShowMessage((ss as TUserVO).pName);
之後,你想怎麼樣就怎麼樣了。。。。。
呵呵,下次再講講業務邏輯方面吧,希望給做DELPHI三層的兄弟一個參考。源碼下載地:http://www.delphifans.com/SoftView/SoftView_2000.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.