用Delphi实现Delphi中的Observer模式

时间:2013-09-10 21:48:59

标签: delphi interface free observer-pattern invalidoperationexception

首先,大家好,感谢您的帮助。

我尝试使用Interfaces在Delphi中实现Observer模式,因此Object可以同时成为Subject和Observer。

我有一个实现ISubject的类,使用以下方法:

procedure TSomeClass.Attach(const observer: IObserver);
var
  I: Integer;
begin
  if Fobservers = nil then
  begin
    Fobservers := TInterfaceList.Create;
  end;
  if Fobservers.IndexOf(Observer) < 0 then
    Fobservers.Add(Observer);
end;

我跟随乔安娜卡特在http://blogs.teamb.com/joannacarter/2004/06/30/690的例子。

在应用程序中,我实例化一个实现IObserver的对象,并将它附加到TSomeClass对象(它也实现了ISubject)。

然后我从TSomeClass对象调用Notify方法,它可以正常工作。当我尝试FreeAndNil我的Observer对象时,我的问题出现了,因为我得到了一个无效的指针操作,即使我使用了&#39; const&#39;在参数中,当我在调试模式下到达FreeAndNil行时,正确分配了对象,并在通知中设置了所有属性并更改了随机属性。

我注意到,当我打电话给这条线路时,我无法释放我的物体:

Fobservers.Add(Observer);

如果我评论这一行,那么我可以释放我的对象。应用程序中的代码如下所示:

procedure TfrmAlisson.Button2Click(Sender: TObject);
var
  locSomeClass: TSomeClass;
  locObserver: TSomeObserverClass;
  I: Integer;
begin
  locObserver:= TSomeObserverClass.create(394693);
  try
    locSomeClass:= TSomeClass.create(263151);
    try
      locSomeClass.Attach(locObserver);
      locSomeClass.NotifyObservers;
    finally
      FreeAndNil(locSomeClass);
    end;
    ShowMessage(IntToStr(locObserver.SomeProperty)); // This property is changed inside the notify
  finally
    locObserver.Free; // error
  end;
end;

我想知道为什么将IObserver添加到TInterfaceList会导致这种情况(我使用Delphi 2009)。

1 个答案:

答案 0 :(得分:3)

您的TSomeObserverClass很可能是继承自TInterfacedObject

当您在Attach中传递它时,它会以IObserver传递,这就是引用计数开始的位置。当RefCount添加到Fobservers时,它会变为1销毁locSomeClass并使用Fobservers列表再次删除它会导致RefCount降至0.然后,IObserver接口引用后面的实例将被销毁。

这里显示的问题是重现它的最小代码:

var
  obj: TInterfacedObject;
  list: TInterfaceList;
begin
  o := TInterfacedObject.Create;
  try
    list := TInterfaceList.Create;
    list.Add(o);
    list.Free;
  finally
    FreeAndNil(o);
  end;
end;

如果执行此操作,您会在FreeAndNil中看到EInvalidError,因为该实例已被TInterfacedObject中实现的自动引用计数破坏。

如前所述,您不应混合对象和接口引用继承自未实现自动引用计数的类。