OOP基本理论知识

通过进一周对以上三个方面的知识理解和结合相应的应用,个人总结如下:
一、对象技术
 OO:它是一种更接近真实世界的视角来分析问题,使用更接近人们理解真实世界的方法来抽象问题。OO本身是一种认识世界、分析问题、解决问题的方法。而面向对象编程(OOP)是一种将OO应用于编程的方法,是一种非常重要的编程思想。语言并不重要,重要的是编程思想。。
面向对象的特点主要有下列四个方面:
• 抽象性
• 封装性
• 继承(派生)性
• 多态性
 Object Pascal是一种支持OOP的Pascal语言。Delphi构建在Object Pascal的基础之上,而Object Pascal构建在面向对象技术之上。所以在下面的总结中均使用Object Pascal来实现OOP这也是以之应用。
Ⅰ. 抽象性——指对现实世界中某一类实体或事件进行抽象。
“类”是对一类事物的抽象,是创建对象的模板;“对象”是类的实例。但这只是简单的概念解释,要说明它们还必须清楚它们本质。
一个类的结构,它包括字段(也称为域)、方法和属性。

类的声明,用class关键字声明如:
type className = class (ancestorClass) // ancestorClass类的隶属:
//省略为Tobject类(最终祖先类)
memberList //类的成员:域、方法和属性。
end;

示例:
type
TMan = class (Tobject)
  private
FAge:Integer;
Procedure SetAge(Value:Integer);
  public
Name:string;
Constructor create;overload;
Procedure Age:Integer read FAge write SetAge;
  end;

对象即类的实例。它分别通过称为构造函数和析构函数的方法创建和销毁。

构造函数是用来创建和初始化一个实例对象。以指示字constructor开头如:
constructor Create(AOwner: TComponent);// 惯例构造函数通常命名为Create
 
要调用构造函数如:
MyObject := TMyClass.Create;
 
析构函数是用来销毁调用的对象并且释放它的内存。以指示字destructor 开头如:
destructor Destroy; override;

要调用析构函数,必须使用一个实例对象的引用如:
MyObject.Destroy;// 建议用 MyObject.Free;增加安全性。

Ⅱ. 封装性——就是把属性定义和方法都包装于类定义之中,把稳定的部分代码暴露给其他代码,而将可变的部分隐藏起来。
封装的级别
private和protected:它们的成员为类的私有性质,仅有类本身和友元可访问。而protected的成员可以被词该类的所有派生类访问。
public和published: 的成员可以被外界的所有客户代码直接访问。而published的成员可以被Delphi开发环境的Object Inspector所显示。
封装的目的是简化用户接口,隐藏实现细节。所以我们在了解接口之前,先了解OOP继承性、多态性,再来说明接口,从而理解封装和接口这一特点。以之达到学习的OO目的。

Ⅲ. 继承(派生)性——是一种关系,当我们声明一个新类时,可以指定它的父类(基类)。则称它继承了父类或是它父类的派生类。当然自动继承了它的父类的所有成员,且可以声明新成员,也可以重新定义继承下来的成员,但不能删除祖先类定义的成员。
继承关系的语法:
TB = class(TA) //TB从TA继承,TA是基类,而TB是派生类

大多数要设计好一个继承关系,总是弱化基类,强化派生类。失败的继承关系设计,总是让基类拥有比派生类更多的额外的能力,哪怕是一个函数/方法。当这不是绝对的要与项目的具体需求有关。

Object Pascal不支持多继承,多继承是指一个对象能继承两个不同的对象,并包含有两个父对象的所有数据和代码。

Ⅳ. 多态性——是同样的方法名因为调用的方式不同而执行完全不同的例程。
 
方法声明可包含一些特殊指示字的顺序列出:
reintroduce; overload; binding; calling convention; abstract; warning
binding 是virtual、dynamic 或override;
calling convention 是register、pascal、cdecl、stdcall 或safecall;
warning 是platform、deprecated 或library。

方法的绑定机制(先期、后期绑定):
先期绑定——绑定动作发生于程序执行之前。(如:静态方法)
静态方法是默认的方法,当调用一个静态方法时,类或对象被声明的类型决定了哪种实现被执行(编译时决定)。
后期绑定——绑定动作发生于程序执行期根据对象类型来定。(如:虚方法、动态方法)
虚方法和动态方法在声明时要包含virtual 或dynamic 指示字,在派生类中被覆盖。当调用一个被覆盖的方法时,类或对象的实际类型决定了哪种实现被调用(运行时),而不是它们被声明的类型。

虚方法和动态方法在声明如:
TFigure = class
procedure Draw; virtual;  //声明TFigure. Draw的一个虚方法
end;

虚方法的实现是用覆盖方法,使用override 指示字重新声明它就可以了。声明被覆盖的方法时,它的参数的类型和顺序以及返回值(若有的话)必须和祖先类相同如:
TRectangle = class(TFigure)
procedure Draw; override;  // TRectangle. Draw方法覆盖了TFigure. Draw方法
end;
TEllipse = class(TFigure)
procedure Draw; override;  // TEllipse. Draw方法覆盖了TFigure. Draw方法
end;

调用虚方法如:
var
Figure: TFigure;
begin
Figure := TRectangle.Create;
Figure.Draw;          // 调用的是TRectangle.Draw
Figure.Destroy;
Figure := TEllipse.Create;
Figure.Draw;          // 调用的是TEllipse.Draw
Figure.Destroy;
end;
 即序执行期根据类或对象的实际类型决定了哪种方法被调用。

隐藏方法——在声明方法时,如果它和继承的方法具有相同的名称和参数,但不包含override。则新方法仅仅是隐藏了继承下来的方法,并没有覆盖它。这样,两个方法在派生类中都存在,方法名是先期绑定。

重新引入——当隐藏一个先前声明的虚方法时,而加入reintroduce指示字则是重新引入,不给出警告信息如:
procedure Draw; reintroduce;  //父类(TFigure)也有一个Draw方法

抽象方法——是在基类内中定义了一个方法,对自身没有必要编写任何代码,而是在覆盖方法时具体化、实用化。即是虚方法或动态方法,在声明类中没有实现,而是由它的派生类来实现,声明抽象方法时,必须在virtual或dynamic后面使用abstract指示字如:
procedure Draw; virtual; abstract;

只有当抽象方法在一个类中被覆盖时,你才能使用这个类或它的实例进行调用。

重载方法——重新声明的方法和祖先类的方法具有不同的参数的数据类型和数量的方法。重载一个虚方法时,必须使用overload指示字如:
queryEmployee(ID: Integer); overload;
queryEmployee(Name: String); overload;
注:同时声明查询员工过程,使用重载方法可以根据员工ID或Name用同一个过程来实现。调用此方法时,依靠参数来决定到底调用哪一个

注意:作为属性读写限定符的方法不能被重载。

是在理解继承的基础上,可以无条件地用继承来的方法,也可以重新编写方法覆盖原来的方法。即通过覆盖机制来增强或改变对象的行为,来实现多态。

Ⅴ. 接口——接口定义了能被一个类实现的方法,可以把接口看成是抽象方法。即是在接口声明中没有实现,而是由支持接口的类来实现,实现时具体化、实用化。

接口声明与类声明相似,一个接口类型的声明格式如:
type
interfaceName = interface (IInterface)
['{GUID}']   //接口标志
memberList  //接口成员只包括方法和属性,所有成员都是公有的public
end;

接口和类区别:
• 接口被声明为Interface类型,不是class类型。惯例是:接口名从字母I开始,正如类类型名从字母T开始。
• 接口成员只包括方法和属性,所有成员都是公有的(public);
• 接口属性的读(read)和写(write)限定符必须是通过方法来实现的;
• 接口方法不能被声明为virtual、dynamic、abstract 或override。
• 接口增加了一个全局唯一标识符GUID;
GUID:用一个被中括号括起来的字符串表示,是一个16 字节的二进制数。格式如:
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'] //x是一个十六进制的位(0到9或者A到F)
注:在Delphi代码编辑器中可以使用Ctrl+Shift+G来创建GUID

• 接口没有构造函数和析构函数。相应的是QueryInterface、_ AddRef 和_Release 三个方法。
在类中TObject为祖先类,并在其中定义了构造函数和析构函数,而接口中IInterface为祖先接口。是在TInterfacedObject t(在System 单元声明)实现了QueryInterface、_ AddRef 和_Release这三个方法。

实现接口——通过一个实现接口的类来实现,格式如:
ClassName = Class (TInterfacedObject, Interface1, ...,InterfaceN)
MemberList
end;
注:一个实现接口的类必须实现QueryInterface、_AddRef 和_Release 方法。

接口方法别名格式如:
Procedure|Function interface.interfaceMethod = implementingMethod;

接口引用实例如:
实例前提:一个中国人与美国人结婚生下的孩子,是一个中美混血儿。它分另继承了中国人和美国人的血统和文化。
功能说明:如他中国父亲教他中文,母亲教他英文,那么他就会说中文也会说英文。
Type
//定义一个ISpeakChinese接口
ISpeakChinese = interface(IInterface)  
['{12E973FC-4156-464E-9055-D7F2E9C46FE5}']   //接口标志
Function SayHello:String;
end;

//定义一个IBall接口
ISpeakEnglish = interface(IInterface)    
['{7B274D2A-CF6D-45BD-AE12-CE9AF28EDAC0}']   //接口标志
Function SayHello: String;
end;

……
 
//实现多个接口
TAmericanChinese = Class (TInterfacedObject, ISpeakChinese, ISpeakEnglish) //实现接口的类:
//TAmericanChinese
//为同名方法取别名
Function ISpeakChinese.SayHello:ChineseSayHello;
Function ISpeakEnglish.SayHello:English.SayHello;
//接口方法
Function ChineseSayHello: String;
Function EnglishSayHello: String;
end;

implementation

……

Function TAmericanChinese.ChineseSayHello: String;
var
 Dad: ISpeakChinese;
begin
 Dad:= TChinese.Create;
 Result:= Dad.SayHello;  //TChinese.SayHello  Result:= ‘你好!’;
end;

Function TAmericanChinese.EnglishSayHello: String;
begin
 Result:= ‘Hello!’;
end;

//接口引用
……

procedure TForm1.FormClick(Sender: TObject); //新建的一个窗体Form1
var
 Tom: TAmericanChinese;
begin
 Tom:= TAmericanChinese.Create;
try
 showmessage(Tom.ChineseSayHello+ Tom.EnglishSayHello)
finally
   Tom.Free;
end;
end;

Object Pascal不支持多继承,而Delphi中是用接口来实现多继承。如上例中说的多继承问题就是用多接口技术解决。

小结:Delphi的对象通过全面支持继承、封装和多态性,提供了面向对象编程的强大功能。只有超越面向过程转向面向对象,才能够接触到Delphi的核心。

二、组件技术
 组件技术——就是为了实现物理上的封装和切割。

COM(Component Object Model ):是微软提出的组件对象模型,是组件技术的本质。就是实现了一组接口给用户提供服务的载体。接口用GUID来标示,而COM对象用Class ID来标示。相对windows平台而言的。所以在下面的总结中均使用COM来说明组件技术这一应用。

以下用COM组件要求和识意图来说明COM组件。

一个COM组件必须要作到以下的几点:
• COM组件必须以给其它的客户端提供服务的形式而存在,当然,它也可以获取其它的组件的服务;
• COM组件必须以二进制的形式发布;
• COM组件必须隐藏(封装)其内部实现细节;
• COM组件必须将其实现的语言隐藏;
• COM组件必须可以在不妨碍已有用户的情况下被升级;
• COM组件必须是动态链接的;
• COM组件可以动态的插入或卸出应用;
……

 
CoClass是正真的封装接口的部分, 实际上,每一个Coclass都可以是一个COM对象,而且又可以实现多个接口, COM对象是接口的集合。

创建一个COM对象的实例
Function CreateComObject(const ClassID:TGUID):IunKnown;
获取需要的接口针,用as操作符如:
MyIntf := CreateComObject(CLSID_MyServer) as IMyInterface

创建一个COM简单的实例:
1.创建COM服务器
File|New|Other选择ActiveX标签|ActiveX Library,保存这个文件为FJCOM.

2.创建COM组件。
File|New|Other|Automation Object,如下图:


改一下FJComObj单元
function TFJComObj.Test: WideString;
begin
  Result:='你好!';
end;

3.保存以上的就可以创建FJCOM方法如:
Project|Build FJComObj

FJCOM.dll就是生成的COM组件的物理文件。

4.调用COM组件
   调用之前要先进行该COM组件注册如:

Run|Register ActiveX Server

 在调用单元中要引用该COM组件的类型库uses FJCOM_TLB;
procedure TForm1.Button1Click(Sender: TObject);
var
 FJ: IFJComObj;
begin
    FJ := CoFJComObj.Create;
    try
    Button1.Caption:= FJ.Test;
    finally
     FJ:= nil;
   end;
end;

COM+就是把COM、DCOM和MTS的编程模型结合起来,并增加了一些新的特性。

小结:COM是组件技术的本质。COM的实现是以DLL为载体,COM通过接口与客户程序通信,接口必须委托给类实现。

三、UML
UML——统一建模语言。本次学习UML的目的,了解相关标记并能理解用UML标记绘制的各种视图。

总结:抽象性、封装性、继承性和多态性为OOP基本理论知识,而组件技术则是用接口技术实现的,接口技术是对OOP基本理论知识的结合应用。即可以称之为OOP的高级知识;UML图是OOP的完整描述。  


posted on 2006-08-11 15:57  Kouwell  阅读(646)  评论(2编辑  收藏  举报

导航