程式 本文介紹了三層結構應用程式的概念和優點,並結合一個執行個體介紹了如何建立三層結構的ASP應用程式。
一、兩層結構的ASP應用有何缺點
在Browser/Server 應用程式開發領域,微軟公司的IIS/ASP以其強大的功能,良好的擴充能力,及與其它微軟產品的一致性,迅速地流行起來。它能使一個具有VB/VC經驗的程式員,很快地成為一個Web程式員,開發出看上去非常專業的應用。但是,ASP有一個天生的缺點,就是ASP代碼和HTML代碼是混在一起的,ASP程式員既需要考慮與資料庫打交道,需要關心如何與HTML配合,有時還需要用ASP直接產生HTML代碼。其結果是,當程式邏輯足夠複雜時,.asp源檔案非常長;而且,無論客戶提出使用者介面的改變,還是商業邏輯的改變(比如,在考試系統中,"合格"的標準可能從達到60分就算合格,改為進入前100名才算合格),都需要對.asp檔案進行改動,而商業邏輯的改變,很可能需要改動很多檔案。
二、三層結構的概念
在傳統的Client / Server應用中,也存在著上述同樣的問題,多層結構的應用正是在對C/S 結構的總結基礎上產生的,並且也已經擴充到了B/S應用開發領域。 即將應用劃分為三層(可以有更多層,但三層最常見): 使用者介面層,商業邏輯層,資料庫層。 使用者介面層負責處理使用者的輸入和向使用者的輸出,但並不負責解釋其含義(出於效率的考慮,它可能在向上傳輸使用者輸入前進行合法性驗證),這一層通常用前端工具(VB,VC,ASP等)開發;商業邏輯層是上下兩層的紐帶,它建立實際的資料庫連接,根據使用者的請求產生SQL語句檢索或更新資料庫,並把結果返回給用戶端,這一層通常以動態連結程式庫的形式存在並註冊到伺服器的註冊簿(Registry)中,它與用戶端通訊的介面符合某一特定的組件標準(如COM,CORBA),可以用任何支援這種標準的工具開發;資料庫層負責實際的資料存放區和檢索。 有了這樣的結構,上面的問題迎刃而解:還是以考試系統中的合格標準為例,在用戶端所有需要顯示合格人員名單的地方,調用這樣一個函數GetQualifiedList,至於這個函數如何編寫,如何與資料庫打交道,以至訪問的是何種資料庫都與其無關(你一定有過這樣的經曆,在一種資料庫系統上運行得很好的SQL語句,有時換到另一種資料庫系統上必須加以修改); 在中介層DLL中實現這個GetQualifiedList函數,如果使用者對"合格"的定義變了,只需要修改這個函數就可以了,只要此函數的入口參數和返回內容不變,在用戶端不需作任何改動。在這裡,我們看到了物件導向編程的特性之一封裝性的優點,而這一點在開發大型應用時尤其有用--我們可以把開發人員分成兩組,一組負責開發介面層,另一組負責開發商業邏輯層,雙方只要按照事先商定的函數介面,並行地開發就可以,而不必向從前那樣,後面的工作必須等前面的工作完成後才能開始。當然,這樣的開發模式需要很好的項目協調和文檔作支援。
你也許會問,如果我把這些函數些在一個單獨的檔案中,再在需要調用的地方把它包含進來,不是同樣能達到目的嗎? 第一,這種方法效率不高,無論你把這些函數分散到多少個檔案中,當你需要調用其中一個時,總會包含進一些實際上並不需要的函數,這無疑加重了伺服器的負擔,對伺服器效能要求較高的Web應用尤其如此。 而DLL只在需要時才調入記憶體且只調入需要的函數,並且多個應用程式執行個體可以共用同一個DLL執行個體;第二,設想一個員工,有20個屬性(工號,姓名,年齡,性別......),現在給定某工號,要求返回此員工所有資訊。此時如果單純用函數,只能定義20個全域變數,在函數中改變這些變數值,或者定義一個有20個傳參(by reference)參數的函數。顯然,第一種方法很麻煩而一旦增加一個屬性後一種方法就需要更改函數介面。而在一個對象裡,既包含成員方法(即函數和過程),也包括成員屬性。如果我們採用對象的方法,則在函數中只需要改變對象的屬性,在函數外可以直接引用改變了的對象屬性值。 這種方法有些類似第一種方法,但1.屬性值無需在函數外逐一說明;2.這些屬性值只屬於對象,與對象無關的代碼不會無意地改變屬性值;3.一旦對象被釋放,這些值會被一起釋放。
三、如何開發三層結構的ASP應用程式
ASP具有良好的擴充性,我們訪問資料庫時,採用的時ADO對象,訪問檔案時,採用的是檔案系統對象(FSO),其實這時程式已經是三層結構的應用程式了,只不過由於是利用內建的對象而為意識到罷了。這些對象都遵循COM/ActiveX介面,因此我們自己開發的對象也要遵循這個介面。下面,我們就以上文提到的"合格"標準為例,示範如何建立自己的三層結構的ASP應用。
1。在資料庫系統中建立如下資料庫表:
Employee: EMPLID char (5) not null,
Name char (10) not null,
Gender char (1) not null,
Score int not null
此表格儲存體員工資訊和考試成績,為簡單起見,這裡只包含工號,姓名和性別三項,並且只有一門考試,EMPLID為主鍵。
2。建立動態連結程式庫
啟動VB(這裡以VB為例,你可以用你喜歡的任何支援ActiveX介面的開發工具開發),建立一工程,工程類型為ActiveX DLL。在工程中建立一個類,取名為Employee。你可以Class Builder可視化的向類中填加屬性和方法,也可以直接手工編輯。首先填加EMPLID屬性如下:
Private msEMPLID as string
Property Let EMPLID(sEMPLID as string)
msEMPLID=sEMPLID
End Property
Property Get EMPLID() as string
EMPLID=msEMPLID
End Property
一般地講,每一個屬性都應該有Property Let和Property Get兩個方法,它們分別當向屬性賦值和讀取屬性值時被調用。如果某個屬性只被賦值而從不被讀取(這種情況多發生在對應資料庫表的主鍵的屬性上),則Property Get方法可以省略。Property Let方法不能省略。你可以仿照上面的程式再建立Name,Gender和Score三個屬性。然後建立如下方法:
Public Sub Create(EMPLID as string)
dim conn as new Connection
dim rs as new Recordset
dim sql as string
"Suppose that you create a DSN in the control panel, the connectionstring property
"can also be dsn-less string
conn.ConnectionString="dsn=dsnname;uid=username;password=pwd"
conn.open
sql="select * from Employee where EMPLID="" & EMPLID & """
with rs
.open sql,conn,1,3
if .eof and .bof then
exit sub
else
msEMPLID=trim(.Fields("EMPLID"))
msName=trim(.Fields("Name"))
msGender=trim(.Fields("Gender"))
msScore=.Fields("Score")
end if
.close
end with
set rs=nothing
conn.close
set conn=nothing
End Sub
這雷根據EMPLID建立Employee對象,注意資料庫中的值是賦給三個私人變數,而不是直接賦值給屬性,如果你單步調試就會發現,給msEMPLID賦值會調用Property Let EMPLID,也就是給屬性賦值。
下面我們再建立一個類Employees,並填加如下方法:
private colQualifiedList as new Collection
private mnCurrentIndex as integer
Public Sub GetQualifiedList()
dim conn as new Connection
dim rs as new Recordset
dim sql as string
"Suppose that you create a DSN in the control panel, the connectionstring property
"can also be dsn-less string
conn.ConnectionString="dsn=dsnname;uid=username;password=pwd"
conn.open
sql="select EMPLID from Employee where Score>=60 order by Score desc"
with rs
.open sql,conn,1,3
if .eof and .bof then
exit sub
else
do while not .eof
dim oEmployee as new Employee
oEmployee.Crea