遇到一个严重的问题,关于接口 (90分)

  • 主题发起人 主题发起人 sansong089
  • 开始时间 开始时间
S

sansong089

Unregistered / Unconfirmed
GUEST, unregistred user!
我定义了一个接口,为了实现像java一样的事件监听。但是不能调用。
比如:
接口为isamp
有一个list里面加的全是实现了isamp的类的对象
但是下面调用不执行
isamp(listeners.items^).abc;

我已经没分了,全部送上!急呀!
 
对,Delphi 里面不能这样用,用纯虚类代替吧,不过要是还同时涉及多重继承的问题,
就比较难办了:(
 
晕 我怕的就是着个,谁可以给个替代的办法呀!

谢谢大家了!
 
我就是想实现,当某个值改变是进行回调。
 
已经找到解决方案:) 问题就出在 Delphi 会自动管理接口的生命周期,于是,
你在保存该接口的引用的时候应该人为地增加其引用计数:

unit TestUnit;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
IObserver = interface(IInterface)
procedure Update(const Msg: string);
end;

TBookObserver = class(TInterfacedObject, IObserver)
public
procedure Update(const Msg: string);
destructor Destroy
override;
end;

TNewspaperObserver = class(TInterfacedObject, IObserver)
public
procedure Update(const Msg: string);
destructor Destroy
override;
end;

TfrmMain = class(TForm)
btnRegObserver: TButton;
btnNotifyHello: TButton;
btnNotifyWorld: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject
var Action: TCloseAction);
procedure btnRegObserverClick(Sender: TObject);
procedure btnNotifyHelloClick(Sender: TObject);
procedure btnNotifyWorldClick(Sender: TObject);
private
FList: TList;
protected
procedure Notify(const Msg: string);
public
procedure RegisterObserver(Observer: IObserver);
end;

var
frmMain: TfrmMain;

implementation

{$R *.dfm}

{ TObserver1 }

destructor TBookObserver.Destroy;
begin
ShowMessage('Book Observer Destroyed');

inherited;
end;

procedure TBookObserver.Update(const Msg: string);
begin
ShowMessage(Format('BookObserver updated: [%s]', [Msg]));
end;

{ TObserver2 }

destructor TNewspaperObserver.Destroy;
begin
ShowMessage('Newspaper Observer Destroyed');

inherited;
end;

procedure TNewspaperObserver.Update(const Msg: string);
begin
ShowMessage(Format('TNewspaperObserver updated: [%s]', [Msg]));
end;

{ TfrmMain }

procedure TfrmMain.FormCreate(Sender: TObject);
begin
FList := TList.Create;
end;

procedure TfrmMain.FormClose(Sender: TObject
var Action: TCloseAction);
begin
FList.Free;
end;

procedure TfrmMain.RegisterObserver(Observer: IObserver);
begin
Observer._AddRef
// [red]关键就在这一句![/red]
FList.Add(Pointer(Observer));
end;

procedure TfrmMain.Notify(const Msg: string);
var
Index: Integer;
begin
for Index := 0 to FList.Count - 1 do
begin
IObserver(FList[Index]).Update(Msg);
end;
end;

procedure TfrmMain.btnRegObserverClick(Sender: TObject);
begin
RegisterObserver(TBookObserver.Create);
RegisterObserver(TNewspaperObserver.Create);
RegisterObserver(TNewspaperObserver.Create);
RegisterObserver(TBookObserver.Create);
end;

procedure TfrmMain.btnNotifyHelloClick(Sender: TObject);
begin
Notify('Hello');
end;

procedure TfrmMain.btnNotifyWorldClick(Sender: TObject);
begin
Notify('World');
end;

end.

完整示例源代码(含可执行程序共171K)可在这里下载:
http://www.01cn.net/cgi-bin/topic_show.cgi?id=1109&pg=1&age=0&bpg=1
 
另,要是仅仅想实现回调而已,可以参考 VCL 中 TXXX.OnClick 的实现:)
 
beta大哥,_AddRef是受保护的,我们自己调用会不会打乱,它本身的机制,引起其他的问题呀?
 
呵呵,_AddRef 被暴露出来就是让程序员可以自行控制其生命周期的:)
换句话说,用它是为了让你避免问题,就象我上面举的例子一样,没有才
不行:)
 
接受答案了.
 
后退
顶部