第一章 回到從前
VCL的設計目標是爲了幫助windows開發人員簡化開發流程,提供組件和麪向對象的方式進行軟件開發的工作。
第二章 Borland VCL Framework的誕生
由於Borland有了從OWL學習到的經驗和教訓,以及當時Microsoft VBX組件架構過於複雜和不易擴充的問題,因此Chuck在VCL Framework設計之初便設定了下面數個目標:
使用單一繼承架構以避免陷入c++多重繼承的問題,同時這也有助於簡化Delphi編譯器的開發工作
VCL Framework 必須不限於16位或是32位平臺
VCL Framework 必須提供開發的組件架構,以允許程序員自定義組件
VCL Framework 必須進化成在可設計時期提供功能的 Framework
VCL Framework必須使用PME(Property-Event-Method)模型
VCL Framework必須使用面向對象技術來設計和實現
VCL Framework必須完善地封裝和分派窗口消息
第三章 面向對象程序語言和Framework
有了TComponent作爲組件的基礎父類之後,VCL控件類可以直接從TComponent類繼承下來嗎?這是一個非常關鍵的問題,因爲這牽涉到Framework架構設計的問題。讓我們討論一下,也讓我們先脫離Borland工程師的想法而思考一下。
1. 如果讓VCL控件類直接從TComponent繼承下來,那麼由於VCL Framework在設計之初就是封裝Windows API以及Windows的對象,因此如果我們聲明一個TWinComponent類從TComponent繼承下來:
TWinComponent = class( TComponent )
....
end;
接着再聲明各種VCL控件類從TWinComponet繼承下來:
TButton = class( TWinComponent )
...
end;
TListBox = class( TWinComponent )
...
end;
...
這樣的設計可以在TWinComponent類中聲明和實現所有VCL控件需要的基礎服務,至於每一個VCL控件特有的服務則是由每一個特定的VCL控件類來提供。如此一來TWinComponent可以設計成聲明許多的虛擬方法,並且在這些虛擬方法中提供基礎的實現程序代碼,再由VCL控件類來改寫這些基礎並且核心的虛擬方法。例如在Windows中控制窗口特性的WNDCLASSSA 數據類型是每一個Windows控制對象都必須填入的,並且每一個控件都需要填入不同的數值。因此TWinComponent可以定義類似如下的虛擬方法CreateParams,在TWinComponent中的CreateParams虛擬方法中可以在WNDCLASSA數據類型中填入大多數VCL控件共通的信息,而TWinComponent的派生類則可以改寫CreateParams再填入不同的信息。
TWinComponent = class( TComponent )
...
procedure CreateParams( var Params: TCreateParams ); virtual;
end;
TButton = class( TWinComponent )
...
procedure CreateParams( var Params: TCreateParams ); override;
end;
TListBox = class( TWinComponent )
...
procedure CreateParams( var Params : TCreateParams ); overrride;
end;
...
依照這樣的設計思想可以讓TWinComponent和派生的VCL控件類正確地封裝Windows控件。但是這樣的設計架構讓VCL Framework和windows操作系統有着太緊密相依的關係,而且有着下面數項違反成爲通用Framework的缺點:
- 沒有彈性的設計架構。如果採用核心通用類(TWinComponent)、直接繼承的實體Windows控件類(例如封裝Windows的Edit,ListBox等控件),那麼VCL Framework將很難再加入其它種類的控件類,因爲如此一來定義在TWinComponent中的數據結構或是虛擬方法直接受到Windows平臺和Windows控件的設計思想影響。
- 無法提供開發人員簡易的實現自定義VCL組件的功能,因爲在TWinComponent和派生類直接沒有提供任何可讓開發人員繼承和實現自定義VCL類的機會。
- 由於在Windows 3.x 和Windows95/98的時代Windows控件的Handle值都共享一塊極小的系統內存(Win95 64K, Win98 128K),因此係統可供使用Wndows控件有一定的限制。如果讓每一個實體Windows控件類直接從TWInComponent繼承下來,則TWinComponent一定得定義代表Windows控件的Handle值,那麼着將讓VCL Framework能夠提供VCL控件種類受到WIndows控件的限制,而且會浪費寶貴的系統Handle資源。這樣講讓VCL Framework無法提供不使用Windows Handle值的自定義VCL控件。
TControl = Class( TComponent )
//鼠標服務
//光標服務
//事件服務
...
end;
TWinControl = class( TControl )
...
end;
TVCLControl = class( TControl )
...
end;
TListBox = class( TWinControl )
...
end;
第四章 VCL Framework和窗口消息
VCL Framework提供的窗口消息封裝機制必須解決下面的問題,
1. 如何把窗口消息正確分派到發生的窗口和控件中?
2. 窗口消息如何分配給封裝控件的VCL封裝類?
上面第一件工作如圖 4-1所示,在VCL Framework之中必須提供一種方法能夠根據窗口消息自動分配給不同的VCL封裝類。
關鍵字: type
功能:聲明類型,常用來聲明接口、類、結構、函數、自定義類型。
{ 1.聲明接口 }
type
IMalloc = interface(IInterface) //說明見下(1.1)
['{00000002-0000-0000-C000-000000000046}'] //說明見下(1.2)
function Alloc(Size: Integer): Pointer; stdcall;//說明見下(1.3)
function Realloc(P: Pointer; Size: Integer): Pointer; stdcall;
procedure Free(P: Pointer); stdcall;
function GetSize(P: Pointer): Integer; stdcall;
function DidAlloc(P: Pointer): Integer; stdcall;
procedure HeapMinimize; stdcall;
end;
{ 2.聲明類 }
type
TMyObject1 = class(TObject)//說明見下(2.1)
end;
type
TMyObject2 = Object(父類)//說明見下(2.2)
end;
{ 3.聲明類指針 }
Type
TStudent = Object(父類)
Private
FName:string;
Protected
Public
Procedure Find;
end;
Pstudent = ^TStudent; //聲明類指針
var
P:PStudent;
begin
New(P);
P^.FName:= ' ';
.......
........
Dispose(p);
end;
{ 4.聲明結構 }
type
TMyRecord = record
Name:String;
Sex:String[2];
Age;Byte;
end;
{ 5.聲明函數 }
type
//函數聲明的一種方式,定義一個函數當作類型,允許這個函數被定義作爲參數用於子程序。
TMyFunc = function(I: Integer): string;
{ 6.聲明自定義類型 }
type
TCol = (cItemA, cItemB, cItemC);//枚舉類型
TColSet = set of TCol;//定義有序數的子界。定義了一個整數或字符的範圍。詳見Set關鍵詞。
TLatter = 'A' .. 'Z';//定義字符範圍
TInt = Integer;//類似C語言的宏,用TInt代替Integer
第10章 VCL Framework的演化——VCL.net
當VCL Framework在移植稱VCL.net時便面臨一個抉擇,那就是對於.NET Framework中提供類似VCL Framework的類,到底VCL.NET應該使用.NET Framework的類呢,還是繼續使用自己的類?最後VCL.NET覺得使用.NET Framework使用的類,並且搭配前面介紹的Helper Class以及Adapter設計模式來利用.NET Framework提供的類服務而又保持了和VCL Framework兼容的類接口。這是一個非常有技巧的設計,因爲VCL Framework中許多的類和Win32以及Windows 消息綁定得太緊密,因此如果VCL.NET能夠通過這次的.NET Framework以更兼容的讓是來移植,那麼將會是一個比較好的選擇,也可以節省VCL.NET重新再.NET 中實現這些緊密相依的類。
因此在VCL.NET中我們可以看到TObject已經定義成.NET的System.Object,並且經由TObjectHelper來提供兼容性,TInterfacedObject類也重新定義成是TObject也就是System.Object。
type
TObject = System.Object;
TCustomAttribute = System.Attribute
TInterfacedObject = TObject;
此外在VCL Framework中提供持久化重要功能的TPersistent 類也被定義成爲是.NET的System.MarshalByRefObject,因爲System.MArshalByRefObject提供了類似並且更爲完整的持久化功能。
TPersistent = System.MarshalByRefObject;
爲了維持兼容性,因而VCL Framework中有大量的類使用了TPersistent,因此也定義了TPersistent的Helper Class。
TPersistentHelper = class helper( TObjectHelper ) for TPersistent
此外如果讀者還記得前面討論持久化的章節,那麼就會記得TPersistent也是用了Adapter設計模式在和VCL Framework兼容的接口以.NET 的持久化功能來實現。