19.2.1.5 編寫部件的面向?qū)ο蠹夹g(shù)
部件使用者在Delphi環(huán)境中開發(fā),將遇到在包含數(shù)據(jù)和方法的對象。他們將在設(shè)計階段和運行階段操作對象,而編寫部件將比他們需要更多的關(guān)于對象的知識,因此,你應當熟悉Delphi的面向?qū)ο蟮某绦蛟O(shè)計。
1. 建立部件
部件用戶和部件編寫者最基本的區(qū)別是用戶處理對象的實例,而編寫者創(chuàng)建新的對象類型。這個概念是面向?qū)ο蟪绦蛟O(shè)計的基礎(chǔ)。例如,用戶創(chuàng)建了一個包含兩個按鈕的窗體,一個標為OK,另一個標為Cancel,每個都是TButton的實例,通過給Text、default和Cancel等屬性賦不同的值,給OnClick事件賦予不同的處理過程,用戶產(chǎn)生了兩個不同的實例。
建立新部件一般有兩個理由
● 改變類型的缺省情況,避免反復
● 為部件增加新的功能
目的都是為了建立可重用對象。如果從將來重用的角度預先計劃和設(shè)計,能節(jié)省一大堆將來的工作。
在程序設(shè)計中,避免不必要的重復是很重要的。如果發(fā)現(xiàn)在代碼中一遍又一遍重寫相同的行,就應當考慮將代碼放在子過程或函數(shù)中,或干脆建立一個函數(shù)庫。
設(shè)計部件也是這個道理,如果總是改變相同的屬性或相同的方法調(diào)用,那應創(chuàng)建新部件。
創(chuàng)建新部件的另一個原因是想給已有的部件增加新的功能。你可以從已有部件直接繼承(如ListBox)或從抽象對象類型繼承(如TComponent,TControl)。你雖然能為部件增加新功能,但不能將原有部件的屬性移走,如果要這樣做的話,就從該父對象的祖先對象繼承。
2. 控制部件的訪向
Object Pascal語言為對象的各部分提供了四個級別的訪問控制。訪問控制讓你定義什么代碼能訪問對象的哪一部分。通過描述訪問級別,定義了部件的接口。如果合理安排接口,將提高部件的可用性和重用性。
除非特地描述,否則加在對象里的域、方法和屬性的控制級別是published,這意味著任何代碼可以訪問整個對象。
下表列出各保護級別:
表19.2 對象定義中的保護級別
━━━━━━━━━━━━━━━━━━━
保護級 用處
───────────────────
private 隱藏實現(xiàn)細節(jié)
protected 定義開發(fā)者接口
public 定義運行時接口
published 定義設(shè)計時接口
━━━━━━━━━━━━━━━━━━━
所有的保護級都在單元級起作用。如果對象的某一部分在庫單元中的一處可訪向,則在該庫單元任意處都可訪向。
、 隱藏實現(xiàn)細節(jié)
如果對象的某部分被聲明為private,將使其它庫單元的代碼無法訪問該部分,但包含聲明的庫單元中的代碼可以訪問,就好象訪問public一樣,這是和C++不同的。
對象類型的private部分對于隱藏詳細實現(xiàn)是很重要的。既然對象的用戶不能訪問,private部分,你就能改變對象的實現(xiàn)而不影響用戶代碼。
下面是一個演示防止用戶訪問private域的例子:
unit HideInfo;
interface
uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,
Dialogs;
type
TSecretForm = class(TForm) { 聲明新的窗體窗口 }
procedure FormCreate(Sender: TObject);
private { declare private part }
FSecretCode: Integer; { 聲明private域 }
end;
var
SecretForm: TSecretForm;
implementation
procedure TSecretForm.FormCreate(Sender: TObject);
begin
FSecretCode := 42;
end;
end.
unit TestHide; { 這是主窗體庫單元 }
interface
uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,
Dialogs, HideInfo; { 使用帶TSecretForm聲明的庫單元 }
type
TTestForm = class(TForm)
procedure FormCreate(Sender: TObject);
end;
var
TestForm: TTestForm;
implementation
procedure TTestForm.FormCreate(Sender: TObject);
begin
SecretForm.FSecretCode := 13; {編譯過程將以"Field identifier expected"錯誤停止}
end;
end.
⑵ 定義開發(fā)者接口
將對象某部分聲明為protected,可使在包含該部件聲明的庫單元之外的代碼無法訪問,就象private部分。protected部分的不同之處是,某對象繼承該對象,則包含新對象的庫單元可以訪問protected部分,你能使用protected聲明定義開發(fā)者的接口。也就是說。對象的用戶不能訪向protected部分,但開發(fā)者通過繼承就可能做到,這意味著你能通過protected部分的可訪問性使部件編寫者改變對象工作方式,而又不使用戶見到這些細節(jié)。
、 定義運行時接口
將對象的某一部分定義為public可使任何代碼訪問該部分。如果你沒有對域方法或?qū)傩约右詐rivate、protected、public的訪問控制描述。那么該部分就是published。
因為對象的public部分可在運行時為任何代碼訪問,因此對象的public部分被稱為運行接口。運行時接口對那些在設(shè)計時沒有意義的項目,如依靠運行時信息的和只讀的屬性,是很有用的。那些設(shè)計用來供用戶調(diào)用的方法也應放在運行時接口中。
下例是一個顯示兩個定義在運行時接口的只讀屬性的例子:
type
TSampleComponent = class(TComponent)
private
FTempCelsius: Integer; { 具體實現(xiàn)是private }
function GetTempFahrenheit: Integer;
public
property TempCelsius: Integer read FTempCelsius; { 屬性是public }
property TempFahrenheit: Integer read GetTempFahrenheit;
end;
function GetTempFahrenheit: Integer;
begin
Result := FTempCelsius * 9 div 5 + 32;
end;
既然用戶在設(shè)計時不能改變public部分的屬性的值,那么該類屬性就不能出現(xiàn)在Object Inspector窗口中。
、 定義設(shè)計時接口
將對象的某部分聲明為published,該部分也即為public且產(chǎn)生運行時類型信息。但只有published部分定義的屬性可顯示在Object Inspector窗口中。對象的published部分定義了對象的設(shè)計時接口。設(shè)計時接口包含了用戶想在設(shè)計時定制的一切特征。
下面是一個published屬性的例子,因為它是published,因此可以出現(xiàn)在Object Inspector窗口:
TSampleComponent = class(TComponent)
private
FTemperature: Integer; { 具體實現(xiàn)是 private }
published
property Temperature: Integer read FTemperature write FTemperature; { 可寫的 }
end;
3. 派送方法
派送(Dispatch)這個概念是用來描述當調(diào)用方法時,你的應用程序怎樣決定執(zhí)行什么樣的代碼,當你編寫調(diào)用對象的代碼時,看上去與任何其它過程或函數(shù)調(diào)用沒什么不同,但對象有三種不同的派送方法的方式。
這三種派送方法的類型是:
● 靜態(tài)的
● 虛擬的
● 動態(tài)的
虛方法和動態(tài)方法的工作方式相同,但實現(xiàn)不同。兩者都與靜態(tài)方法相當不同。理解各種不同的派送方法對創(chuàng)建部件是很有用的。
相關(guān)推薦:2010年9月計算機等級考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |