delphi - 接口(interface)委托(delegate)+重写

标签 delphi oop interface delegation

由于Delphi中缺乏多重继承,我需要使用接口(interface)委托(delegate)。这对我来说是一个非常新的主题,我在将重写与接口(interface)委托(delegate)结合起来时遇到了问题。

TMyNode 必须继承自 TBaseClass 并需要实现 IAddedStuff 。我希望在 TAddedStuffDefaultImplementation 中拥有 IAddedStuff 的所有函数的默认实现,因此我不需要到处都有重复的 getter/setter 代码。因此,我使用 DefaultBehavior 委托(delegate)了这些事情。

问题是, TAddedStuffDefaultImplementation 应该有虚拟方法,所以我想直接在 TMyNode 中重写它们。如果我写 FDefaultImplementation: TAddedStuffDefaultImplementation; 而不是 FDefaultImplementation: IAddedStuff; ,这确实有效。

但是现在,由于某些原因TAddedStuffDefaultImplementation会增加x: TBaseClass;的Ref-Counter,因此无法释放它。我该怎么办?

我的简化复制代码如下:

program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  IAddedStuff = interface(IInterface)
  ['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
    function GetCaption: string; {virtual;}
  end;

  TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
    function GetCaption: string; virtual;
  end;

  TBaseClass = class(TInterfacedObject);

  TMyNode = class(TBaseClass, IAddedStuff)
  private
    FDefaultImplementation: TAddedStuffDefaultImplementation;
  public
    property DefaultBehavior: TAddedStuffDefaultImplementation read FDefaultImplementation
      write FDefaultImplementation implements IAddedStuff;
    destructor Destroy; override;

    // -- IAddedStuff
    // Here are some functions which I want to "override" in TMyNode.
    // All functions not declared here, should be taken from FDefaultImplementation .
    function GetCaption: string; {override;}
  end;

{ TAddedStuffDefaultImplementation }

function TAddedStuffDefaultImplementation.GetCaption: string;
begin
  result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;

{ TMyNode }

destructor TMyNode.Destroy;
begin
  if Assigned(FDefaultImplementation) then
  begin
    FDefaultImplementation.Free;
    FDefaultImplementation := nil;
  end;

  inherited;
end;

function TMyNode.GetCaption: string;
begin
  Result := 'OK: Caption overridden';
end;

var
  x: TBaseClass;
  gn: IAddedStuff;
  s: string;
begin
  x := TMyNode.Create;
  try
    TMyNode(x).DefaultBehavior := TAddedStuffDefaultImplementation.Create;
    Assert(Supports(x, IAddedStuff, gn));
    WriteLn(gn.GetCaption);
  finally
    WriteLn('RefCount = ', x.RefCount);
    // x.Free; // <-- FREE fails since FRefCount is 1
  end;
  ReadLn(s);
end.

最佳答案

如果您要委托(delegate) IAddedStuff,那么您还应该在另一个类上实现非默认行为,并通过构造函数注入(inject)传递它。

此外,如果您混合对象和接口(interface)引用,请确保引用计数不冲突。当使用接口(interface)委托(delegate)时,容器对象的引用会发生变化。

program Project1;

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils;

type
  IAddedStuff = interface(IInterface)
  ['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
    function GetCaption: string; {virtual;}
  end;

  TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
    function GetCaption: string; virtual;
  end;

  TAddedStuffOverriddenImplementation = class(TAddedStuffDefaultImplementation)
    function GetCaption: string; override;
  end;

  TBaseClass = class(TInterfacedPersistent);

  TMyNode = class(TBaseClass, IAddedStuff)
  private
    FAddedStuff: IAddedStuff;
    property AddedStuff: IAddedStuff read FAddedStuff implements IAddedStuff;
  public
    constructor Create(const addedStuff: IAddedStuff);
  end;

{ TAddedStuffDefaultImplementation }

function TAddedStuffDefaultImplementation.GetCaption: string;
begin
  result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;

{ TAddedStuffOverriddenImplementation }

function TAddedStuffOverriddenImplementation.GetCaption: string;
begin
  Result := 'OK: Caption overridden';
end;

{ TMyNode }

constructor TMyNode.Create;
begin
  FAddedStuff := addedStuff;
end;

var
  x: TBaseClass;
  gn: IAddedStuff;
begin
  x := TMyNode.Create(TAddedStuffOverriddenImplementation.Create);
  try
    Assert(Supports(x, IAddedStuff, gn));
    WriteLn(gn.GetCaption);
  finally
    x.Free;
  end;
  Readln;
  ReportMemoryLeaksOnShutdown := True;
end.

编辑:

经过评论中的讨论,我提出以下建议:

program Project1;

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils;

type
  IAddedStuff = interface(IInterface)
  ['{9D5B00D0-E317-41A7-8CC7-3934DF785A39}']
    function GetCaption: string;
  end;

  TAddedStuffDefaultImplementation = class(TInterfacedObject, IAddedStuff)
    function GetCaption: string; virtual;
  end;

  TBaseClass = class(TInterfacedPersistent);

  TMyNode = class(TBaseClass, IAddedStuff)
  private
    FAddedStuff: IAddedStuff;
    property AddedStuff: IAddedStuff read FAddedStuff implements IAddedStuff;
  public
    constructor Create;
  end;

  TAddedStuffOverriddenImplementation = class(TAddedStuffDefaultImplementation)
  private
    FMyNode: TMyNode;
  public
    constructor Create(AMyNode: TMyNode);
    function GetCaption: string; override;
  end;

{ TAddedStuffDefaultImplementation }

function TAddedStuffDefaultImplementation.GetCaption: string;
begin
  result := 'PROBLEM: CAPTION NOT OVERRIDDEN';
end;

{ TMyNode }

constructor TMyNode.Create;
begin
  FAddedStuff := TAddedStuffOverriddenImplementation.Create(Self);
end;

{ TAddedStuffOverriddenImplementation }

constructor TAddedStuffOverriddenImplementation.Create(AMyNode: TMyNode);
begin
  FMyNode := AMyNode;
end;

function TAddedStuffOverriddenImplementation.GetCaption: string;
begin
  Result := 'OK: Caption overridden';
end;


var
  x: TBaseClass;
  gn: IAddedStuff;
begin
  x := TMyNode.Create;
  try
    Assert(Supports(x, IAddedStuff, gn));
    WriteLn(gn.GetCaption);
  finally
    x.Free;
  end;
  ReadLn;
  ReportMemoryLeaksOnShutdown := True;
end.

关于delphi - 接口(interface)委托(delegate)+重写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24454572/

相关文章:

delphi - 如何确定用户帐户是否是 AD 组的(间接)成员?

c# - 从未知接口(interface)获取属性

listview - 如何更改 TListGroups 中的组顺序?

delphi - TIdHTTPServer 在我的 DUnit 测试中激活它时引发 EThread 错误 6

c# - 在应用策略模式时,是否有一种好的方法可以避免某些子类中未使用的方法参数?

php - 我应该还是不应该使用 getter 和 setter 方法?

javascript - 如何使类的属性不区分大小写?

c# - 如何在另一个窗体(如 Visual Studio)中显示窗体

java - 实例化另一个抽象类的内部抽象类

delphi - 如果我不将函数的返回值保存在变量中,则函数的返回值存储在内存中的哪里?