Welcome

首页 / 软件开发 / Delphi / 第十九章-Delphi自定义部件开发(一)(3)

第十九章-Delphi自定义部件开发(一)(3)2007-05-0719.2.1.5 编写部件的面向对象技术

部件使用者在Delphi环境中开发,将遇到在包含数据和方法的对象。他们将在设计阶段和运行阶段操作对象,而编写部件将比他们需要更多的关于对象的知识,因此,你应当熟悉Delphi的面向对象的程序设计。

1. 建立部件

部件用户和部件编写者最基本的区别是用户处理对象的实例,而编写者创建新的对象类型。这个概念是面向对象程序设计的基础。例如,用户创建了一个包含两个按钮的窗体,一个标为OK,另一个标为Cancel,每个都是TButton的实例,通过给Text、default和Cancel等属性赋不同的值,给OnClick事件赋予不同的处理过程,用户产生了两个不同的实例。

建立新部件一般有两个理由

● 改变类型的缺省情况,避免反复

● 为部件增加新的功能

目的都是为了建立可重用对象。如果从将来重用的角度预先计划和设计,能节省一大堆将来的工作。

在程序设计中,避免不必要的重复是很重要的。如果发现在代码中一遍又一遍重写相同的行,就应当考虑将代码放在子过程或函数中,或干脆建立一个函数库。

设计部件也是这个道理,如果总是改变相同的属性或相同的方法调用,那应创建新部件。

创建新部件的另一个原因是想给已有的部件增加新的功能。你可以从已有部件直接继承(如ListBox)或从抽象对象类型继承(如TComponent,TControl)。你虽然能为部件增加新功能,但不能将原有部件的属性移走,如果要这样做的话,就从该父对象的祖先对象继承。

2. 控制部件的访向

Object Pascal语言为对象的各部分提供了四个级别的访问控制。访问控制让你定义什么代码能访问对象的哪一部分。通过描述访问级别,定义了部件的接口。如果合理安排接口,将提高部件的可用性和重用性。

除非特地描述,否则加在对象里的域、方法和属性的控制级别是published,这意味着任何代码可以访问整个对象。

下表列出各保护级别:

表19.2 对象定义中的保护级别

━━━━━━━━━━━━━━━━━━━

保护级 用处

───────────────────

private 隐藏实现细节

protected 定义开发者接口

public 定义运行时接口

published 定义设计时接口

━━━━━━━━━━━━━━━━━━━

所有的保护级都在单元级起作用。如果对象的某一部分在库单元中的一处可访向,则在该库单元任意处都可访向。

⑴ 隐藏实现细节

如果对象的某部分被声明为private,将使其它库单元的代码无法访问该部分,但包含声明的库单元中的代码可以访问,就好象访问public一样,这是和C++不同的。

对象类型的private部分对于隐藏详细实现是很重要的。既然对象的用户不能访问,private部分,你就能改变对象的实现而不影响用户代码。

下面是一个演示防止用户访问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.

⑵ 定义开发者接口

将对象某部分声明为protected,可使在包含该部件声明的库单元之外的代码无法访问,就象private部分。protected部分的不同之处是,某对象继承该对象,则包含新对象的库单元可以访问protected部分,你能使用protected声明定义开发者的接口。也就是说。对象的用户不能访向protected部分,但开发者通过继承就可能做到,这意味着你能通过protected部分的可访问性使部件编写者改变对象工作方式,而又不使用户见到这些细节。

⑶ 定义运行时接口

将对象的某一部分定义为public可使任何代码访问该部分。如果你没有对域方法或属性加以private、protected、public的访问控制描述。那么该部分就是published。

因为对象的public部分可在运行时为任何代码访问,因此对象的public部分被称为运行接口。运行时接口对那些在设计时没有意义的项目,如依靠运行时信息的和只读的属性,是很有用的。那些设计用来供用户调用的方法也应放在运行时接口中。

下例是一个显示两个定义在运行时接口的只读属性的例子:

type

TSampleComponent = class(TComponent)

private

FTempCelsius: Integer; { 具体实现是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;