接口是什么(100分)

  • 主题发起人 主题发起人 千层血
  • 开始时间 开始时间

千层血

Unregistered / Unconfirmed
GUEST, unregistred user!
1. 我现在在做一个程序,当一个按钮被按下了后,程序开始一个复杂的运
算我打算在程序进行计算的时显示一个动画(AVI),可是实际发现并不是
我想的那样,再运行的时候AVI基本上不动的,只有当代码运行到
APPLICATION.ProcessMessages (在品目上显示当前计算的结果)时才动一针,
画面很不流畅,怎么才能在这个时候让画面流畅呢(能不用线程就好了)
2. 还有一个比较低,要是能给我点相关的资料看看也行(yj5637899@21cn.com)
说定义两个接口
Type
IFoo= interfce
['{xxxxxxxxx-xxxxxx-xxxxx-xxxxxx-xxxxx}']
function F1:inter;
End;
Type
IBar= interfce(IFoo)
['{xxxxxxxxx-xxxxxx-xxxxx-xxxxxx-xxxxx}']
function F2:inter;
End;
说下面这段代码就能在一个TFooBar 中实现IFoo和IBar 借口
Type
TFooBar = Class(Tinterfacedobject,IFoo,IBar)
function F1 : integer;
function F2 :integer;
End;
function TFooBar.F1 :integer;
Begin
Result := 0;
End;
function TFooBar.F2 :integer;
Begin
Result := 0;
End;
说就实现了那两个接口,我N思不得其接,不就是定义一个类,
里面有两个成员(不知道没有声明是算共有还是私有),
他哪一点实现借口了,摆脱大佬说的浅一点~~谢谢
 
From Code6421
浅谈Interface

Write By code6421
多重继承
OOP 的重点在于继承,封装,多型等概念上,其中以继承最受争议,尤其是多重继承与单一继承,到目前为止,
至少在实作上许多语言都选择了单一继承,原因不外乎多重继承会将整个对象架构复杂化,为了保留多重继承的特性,
Interface(界面) 的概念就成为最好的选择,标准的OO 继承课题就是父母与子女之间的关系,子女继承了父与母的的特性,
此为多重继承,但我们都知道,现实上子女并不会拥有父母的所有特性及能力,但在多重继承概念上,子可以向上转型为父,
也可以向上转型为母,而这就是多重继承受争议的地方.
图:多重继承




由上面的图我们可以发现,子同时继承了父与母两个类别,也就是说子拥有了父与母类别所有的
特性,让我们以一个较简单的方式来说,当父类别拥有抽烟的特性,那在多重继承的观念下
,子类别必然也有抽烟的特性,但我们都知道这并不是绝对的.因此我们需要让子类别选择是否会抽烟,基于这个理由,
我们得把父类别的抽烟特性定义成可覆载,这样子类别才能选择是否会抽烟,
如果这类特性不多的话还好,但多的话就很烦人了,所以多重继承下的结果,必定是很沉重的.
 

多重继承的替代品 - Interface

Interface 以支持某种能力(或拥有某种能力) 为主体来取代多重继承,以上面的类别来定义的话,就如下图:

图:以Interface 实作取代继承




从上图来看,你可以发现子直接继承人类别,而不是继承父或母,那子类别如何拥有父与母的特性呢? 例如子类别要拥有抽烟的能力?



上图中我们称之为子类别继承了人类别并实作了抽烟这个接口,我们也可以说子是个人,拥有抽烟的能力,
这样的做法是否比上面的多重继承更符合现实呢? 呵,我把这个问题留给你,我可不想再一次陷入论战中,
回到Interface,基本上Interface 也拥有了继承特性,你可以继承抽烟这个Interface,并加入新的特性
图:Interface 继承



ㄜ…我知道这不太雅,呵,你就将就一下吧 :)

因此我们重新定义一下父母子的关系

图:实作继承的Interface



Interface 继承与Class 继承是差不多的,只是Interface 继承了定义而非实体


类别也可以实作多个Interface,例如下图:



 

 

DELPHI(PASCAL) 与Interface
基本上DELPHI 支援Interface 操作,但在DELPHI 6 之前的操作较不直觉,因此容易造成DELPHI 对Interface 支持不足的假象,
庆幸的是在DELPHI 6 中这个问题已经被解决了,这也使得Interface 成为WebSnap 最重要的部份,同时也在VCL 中有相当重的戏份,
下面是你最常看到的Interface 运用:
IMyInterface=interface
['{FE5A34E5-21AB-4120-971B-FDC3241AD55D}']
function SayHello:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface)
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure DoSayHello(Intf:IMyInterface);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TMyObject.SayHello:string;
begin
Result:='Hello';
end;
procedure TForm1.DoSayHello(Intf:IMyInterface);
begin
ShowMessage(Intf.SayHello);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create;
Intf:=(Obj as IMyInterface);
DoSayHello(Intf);
end;
OK,我想这个范例大家都看过了,接下来我们变点不一样的

type
IMyInterface=interface
['{FE5A34E5-21AB-4120-971B-FDC3241AD55D}']
function SayHello:string;
end;
TMyObject=class(TEdit,IMyInterface)
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure DoSayHello(Intf:IMyInterface);
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function TMyObject.SayHello:string;
begin
Result:='Hello';
end;
procedure TForm1.DoSayHello(Intf:IMyInterface);
begin
ShowMessage(Intf.SayHello);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
Intf:=(Obj as IMyInterface);
DoSayHello(Intf);
end;
嘿! 我可没要你照着打哦,这样是不会通过编译的,你得变成这样才行(在DELPHI 5).


procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
Obj.GetInterface(IMyInterface,Intf);
DoSayHello(Intf);
Obj.Free;
end;

GetInterface 是用来取得我们想要的Interface,基本上它会传回一个Boolean 代表是否取得了Interface,
如果你在DELPHI 6 的话,之前未修改过的那一个版本就可以通过编译器,所以啦,DELPHI 6 还是进步了.
其实在DELPHI 6 中正规的写法是这样

procedure TForm1.Button1Click(Sender: TObject);
var
Obj:TMyObject;
Intf:IMyInterface;
begin
Obj:=TMyObject.Create(Self);
if Supports(Obj,IMyInterface,Intf) then
DoSayHello(Intf);
Obj.Free;
end;


如果你在DELPHI 5 中这样写也可以,不过你会发现Supports 除了继承至TinterfacedObject 之外的对象都会传回False,
这是因为DELPHI 5 的的TComponent 并未实作Iunknown(至少在明定上没有),但在DELPHI 6中,TComponent 实做了相当于Iunknown的Iinterface,
所以如果你想要在你的程序中完整运用Interface,建议你还是用DELPHI 6 会较为直觉.
用DELPHI 5 的话还可使用下面的方法来通过编译器

TMyObject=class(TEdit,IMyInterface,IUnknown)


这样你就可以使用as 来转型,可是如果你要使用Supports 的话,Compiler 会丢出一个错误,因此还是使用GetInterface 来的方便一点!



实作多个Interface
做这件事是很简单的,一个类别可以实做一个已上的Interface,这我想你一定早就知道了,
因此在这里我提一下有关实作多个Interface 时的运用.


转型规则

一个类别实作了一个已上的Interface 时,例如X类别实做了A,B,C 三个Interface,因此你可以透过X 取得 A,
同样的,你也可以透过A 取得 B或透过A 取得C,这在COM 中有很详细的定义:
Symmetric(对称) 当你透过A 成功取得 B,那么你也可以透过B 成功取得A
Transitive(递移) 当你透过A 成功取得B,且透过B 成功取得C,那么你也可以透过A 成功取得C.
Reflexive(反身) 使用A 查询 A 必定是成功的.



Delegation(代理)
从DELPHI 4 开始,OO PASCAL 就支持Interface Delegation,这种技术使得实作Interface 变的更有弹性,你可以从下面的范例中看出端倪

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function SayHello:string;
end;
IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function SayHello2:string;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function SayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:TMyObject2;
public
property DelgateObj:TMyObject2 read FDelgateObj implements IMyInterface2;
constructor Create;
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=TMyObject2.Create;
end;
function TMyObject2.SayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.SayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.

重点就在篮色字及红色字的部份,你可以发现我们的TMyObject实作了两个Interface,但你在里面却只找到IMyInterface的定义,
这是因为我们运用了Delgation 将IMyInterface2 导向TMyObject2,而它正是实作IMyInterface2 的类别,这种技术使得主类别简洁许多
,同时也带出了另一种运用:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function SayHello:string;
end;
IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function SayHello2:string;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function SayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:IMyInterface2;
public
property DelgateObj:IMyInterface2 read FDelgateObj write FDelgateObj implements IMyInterface2;
constructor Create;
function SayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=Nil;
end;
function TMyObject2.SayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.SayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.
上面这个范例告诉我们,我们可以指派任何实作了IMyInterface2对象给TmyObject,这就是上面所说的另一种运用.

 

Property In Interface
DELPHI 6 中的说明档标示这个是新功能,但事实上,DELPHI 5 就有这个能力了,没有DELPHI 4,所以不知道她有没有,
基本上这是让你可以在Interface 中宣告Property,我们用一个范例开始:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface=interface
['{2E173B2D-6BE9-4519-8E5F-6DEF400335EC}']
function GetSayHello:string;
property SayHello:string read GetSayHello;
end;
IMyInterface2=interface
['{3FD6CFDF-E028-4FD6-9834-299404C15FFF}']
function GetSayHello2:string;
property SayHello2:string read GetSayHello2;
end;
TMyObject2=class(TInterfacedObject,IMyInterface2)
function GetSayHello2:string;
end;
TMyObject=class(TInterfacedObject,IMyInterface,IMyInterface2)
private
FDelgateObj:IMyInterface2;
public
property DelgateObj:IMyInterface2 read FDelgateObj write FDelgateObj implements IMyInterface2;
constructor Create;
function GetSayHello:string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyObject.Create;
begin
FDelgateObj:=Nil;
end;
function TMyObject2.GetSayHello2:string;
begin
Result:='I am Object2';
end;
function TMyObject.GetSayHello:string;
begin
Result:='I am Object1';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
if Supports(MyObject,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(MyObject,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
end.
我们在Interface 将SayHello,SayHello2 定义为property,而实作这两个Interface 只需实作Get Method就可以了,
这是否使得Interface 的运用又更方便了呢?
DELPHI 6 的Interface 支持已经相当完备了,如果你正巧有DELPHI 6,也正巧要开发软件,
使用Interface 将会使你的软件有更高的延展性,当然! 好好规划也是很重要的.


DELPHI 6 的Interface 与 Variant
DELPHI 6 支持Custom Variants,这是一个非常有用的特色,但它和Interface 有何关系呢?
答案并不在Custom Variants 身上,而是在DELPHI 6 重新实作Variants这件事上,因为这个动作,使得我们下面的程序得以正常运作:

procedure TForm1.Button1Click(Sender: TObject);
var
MyObject:TMyObject;
MyObject2:TMyObject2;
Intf1:IMyInterface;
Intf2:IMyInterface2;
V:Variant;
begin
MyObject:=TMyObject.Create;
MyObject.FDelgateObj:=TMyObject2.Create;
V:=(MyObject as IInterface);
if Supports(V,IMyInterface,Intf1) then
ShowMessage(Intf1.SayHello);
if Supports(V,IMyInterface2,Intf2) then
ShowMessage(Intf2.SayHello2);
end;
这段程序代码隐含着一个意义,就是你可以把任何对象转成IInterface 塞进Variant 中,那对你有何帮助呢? 呵! 我不知道,你慢慢想吧!

给DELPHI 5 使用者
是的,上面所谈的技巧大多可以用DELPHI 5 达到,只是你必须要做一些额外的工作,
例如你可以将Iunknown,Idispatch 指派给Variant 后传递,但传送的如果是TComponent 呢?
你必需想办法将Iunknown 对应到TComponent 上,这就是额外的工作,DELPHI 6 提供我们更直觉的方式,
或许这正是升级DELPH 6 的好借口 :)

最后......................
文中的程序代码如果可以运作的话,那是我写的,如果不能的话,那我不知道是谁写的. :)
 
请下载相关文章,很精彩
http://delphi.mychangshu.com/dispdoc.asp?id=305
 
繁体的哎,读的很困难呀~大哥翻译一下吧~
 
To code6421,

Thank you very much for the nice and simple explaination about Interface.

Here I have a question about your second example:

TMyObject=class(TEdit,IMyInterface)
function SayHello:string;
end;

Why do you use TEdit rather than TInterfacedObject in the class declaration?

I have tried using TButton, it also works. Can you please give some more
comments, or samples.

Best Regards,

ourselves2002@sina.com
 
后退
顶部