delphi类的设计

类包含的内容:属性、方法、事件及类的主要用途:封装、继承、多态;

      先从结构谈起,结构(或叫记录)与类都是一种自定义类型,在使用前都必须先声明一个变量,结构直接使用,内存是自动管理;类只是一个模型,需要根据模型(也就是类)创建(Create)出对象来才能使用,用完后需要手动释放内存(内存使用的规律应该是自动创建自动释放,手动创建手动释放);结构与对象(类的实例)在内存中以不同的方式存放,对象只是一个指针;和结构相比,类拥有更强大的功能;

Type
TMyRecord = record {定义结构}
   d: TDate;
end;

TMyClass = class   {定义类; 虽然这个类没有什么实际意义, 但就是一个类了}
   d: TDate;
end;

var
MyRec: TMyRecord; {声明一个结构变量}
MyCls: TMyClass; {声明一个类变量, 也就是对象}
begin
{使用结构,直接使用}
MyRec.d := Now;
ShowMessage(DateToStr(MyRec.d));     {2008-1-11}
ShowMessage(IntToStr(SizeOf(MyRec))); {8; MyRec 结构的大小是 8}
{使用类}
MyCls := TMyClass.Create;             {需要先手动建立, 因为类需要实例化为对象才可以使用}
MyCls.d := Now;                       {2008-1-11}
ShowMessage(DateToStr(MyCls.d));
ShowMessage(IntToStr(SizeOf(MyCls))); {4; 怎么会是4? 因为 MyCls 对象只是一个指针!}
MyCls.Free;                           {用完后释放}

类的方法:Type
TMyClass = class
procedure MyProc(var x: Integer);
function MyFun (var x: Integer): Integer;
end;
       上面定义了一个TMyClass类其中包含一个函数和一个过程,它们在类里面一般都叫做方法,函数是有返回值的,过程是没有返回值的;这里方法只是定义了还没有实现,必须在本单元的implementation内实现;在使用的时候呢必须先声明一个对象实例,然后才能正确调用里面的方法;

类的字段,属性
//TMyClass1 类里面只有两个字段(变量来到类里面称做字段)
TMyClass1 = class
   FName: string; {字段命名一般用 F 开头, 应该是取 field 的首字母}
   FAge: Integer; {另外: 类的字段必须在方法和属性前面}
end;
{这个类中的两个字段, 可以随便读写; 在实际运用中, 这种情况是不存在的.}

//TMyClass2 类里面包含两个属性(property)、两个方法、两个和 TMyClass1 相同的字段
TMyClass2 = class
strict private
   FName: string;
   FAge: Integer;
procedure SetAge(const Value: Integer);
procedure SetName(const Value: string);
published
property Name: string read FName write SetName;
property Age: Integer read FAge write SetAge;
end;


{ 但这里的字段: FName、FAge 和方法: SetAge、SetName 是不能随便访问的,因为, 它们在 strict private 区内, 被封装了, 封装后只能在类内部使用.属性里面有三个要素: 1、指定数据类型: 譬如 Age 属性是 Integer 类型; 2、如何读取: 譬如读取 Age 属性时, 实际上读取的是 FAge 字段; 3、如何写入: 譬如希尔 Age 属性时, 实际上是通过 SetAge 方法. 属性不过是一个桥.通过属性存取字段 和 直接存取字段有什么区别? 过属性可以给存取一定的限制, 譬如: 一个人的 age 不可能超过 200 岁, 也不会是负数; 一个人的名字也不应该是空值. 看 implementation 区 TMyClass2 类的两个方法的实现, 就增加了这种限制. }

类的事件:

{先定义一个特殊的类型: 一个对象所属的过程类型; 这是建立一个事件的前提}
TMyEvent = procedure of object;
{TMyClass 类}
TMyClass = class
strict private
   FAge: Integer;           {年龄字段}
   FOnHundred: TMyEvent;   {为我们刚刚定义的 TMyEvent 类型指定一个变量: FOnHundred}
procedure SetAge(const Value: Integer);
public
procedure SetOnHundred1; {建立事件将要调用的过程}
procedure SetOnHundred2; {建立事件将要调用的过程}
constructor Create;
property Age: Integer read FAge write SetAge;
property OnHundred: TMyEvent read FOnHundred write FOnHundred; {其实事件也是属性}
{事件命名一般用 On 开始}
end;{在对象建立时, 我们先让事件调用 SetOnHundred1 方法}
constructor TMyClass.Create;
begin
FOnHundred := SetOnHundred1; {在对象建立时, 我们先让事件调用 SetOnHundred1 方法,在使用的过程中也可以让事件调用另一个方法:myClass.OnHundred := myClass.SetOnHundred2}
end;

类的继承:通过继承不用编写任何代码就可以享受现有类的所有属性及功能,并可以在原功能的情况下进行功能扩展;

//下面自定义了两个类, TChild 继承于 TBass
TBass = class
procedure msg1; //父类只有一个方法 msg1
end;TChild = class(TBass)
procedure msg2;
end;
//子类继承父类的方法msg1,也有自己的方法msg2,使用的时候即可以调用父类的方法也可调用自身的
var
c: TChild;
begin
c := TChild.Create;
c.msg1; {调用父类方法}
c.msg2; {调用子类自身方法}
c.Free;
end;

类的封装:封装的目的就是隐藏实现细节、保证数据安全

//这个类中的两个字段没有封装
TMyClass1 = class
   FName: string;
   FAge: Integer;


end; 类的多态:我的理解是同样的一个方法,在不同的类里有不同的实现,实现不同的功能;

//这个类中的两个字段封装了, 外部不能读写
TMyClass2 = class
private
     FName: string;
     FAge: Integer;
//public
end;//那怎么读写? 用属性啊
TMyClass3 = class
private
   FName: String;
   FAge: Integer;
procedure SetAge(const Value: Integer);
procedure SetName(const Value: String);
published
property Name: String read FName write SetName;
property Age: Integer read FAge write SetAge;
end;
{ 现在 TMyClass3 中的两个字段: FName、FAge 和两个方法: SetAge、SetName;都被封装在私有区(private)内, 不允许外部读写, 只能是内部使用.不过, private 的封装在本单元内是无效的! 现在好了, 有了 strict 标识符. }//这个封装好了, 在 private 前加了 strict ; 现在除了自己谁也访问不了私有区.
TMyClass4 = class
strict private
   FName: String;
   FAge: Integer;
procedure SetAge(const Value: Integer);
procedure SetName(const Value: String);
published
property Name: String read FName write SetName;
property Age: Integer read FAge write SetAge;
end;//定义了三个类, 后两个类都继承与第一个类 TBass
TBass = class
procedure alert; virtual; {加上 virtual 指示字, 说明这个方法可能会被修改(或叫覆盖)}
{这种方法叫虚方法}
end;TChild1 = class(TBass)
procedure alert; override; {override 表示修改父类的同名方法}
end;TChild2 = class(TBass)
procedure alert; override;
end;//实现上面的方法:
procedure TBass.alert;
begin
ShowMessage('is Bass');   {同一个方法, 在不同类里有不同的实现}
end;{ TChild1 }
procedure TChild1.alert;
begin
ShowMessage('is TChild1'); {同一个方法, 在不同类里有不同的实现}
end;{ TChild2 }
procedure TChild2.alert;
begin
ShowMessage('is TChild2'); {同一个方法, 在不同类里有不同的实现}
end;//测试:
procedure TForm1.Button1Click(Sender: TObject);
var
bass: TBass; {定义 TBass 的变量}
begin
bass := TBass.Create;   {这里通过父类建立对象 }
bass.alert; {is Bass}
bass := TChild1.Create; {但这里是通过 TChild1 建立对象}
bass.alert; {is TChild1}
bass := TChild2.Create; {但这里是通过 TChild2 建立对象}
bass.alert; {is TChild2}
bass.Free;
end;