使用“匿名”类实现 Delphi 接口

9
我有一个接口。
type IProgressObserver = interface(IInterface)
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
end;

我已经使用命名类实现了接口,如下所示:

type TProgressObserver=class(TInterfacedObject, IProgressObserver)    
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
end;

... implementation of methods go here .....

addProgressObserver(TProgressObserver.Create);

有没有可能在不声明类的情况下创建此接口的实例?像这样(想象中的)代码,它将执行与上面相同的操作:
 addProgressObserver(IProgressObserver.Create()
 begin
   procedure ReportProgress(Progress:Integer)
   begin
     ShowMessage('Progress Observed!');
   end

   procedure ReportError(Message:string)
   begin
     Log(Message);
   end
 end;);

Delphi有匿名过程,但是否有匿名类?

我发现了这个类似的问题,但它是关于Java的。

我正在使用Delphi 2010。

2个回答

17

通过使用匿名方法,您可以变得非常匿名。但是,这样做并没有获得实际的编译器支持,您需要自己声明所有匿名方法类型,然后实现实际的“匿名”类。给定您的 IProgressObserver 接口,实现代码将类似于以下内容:

type
  // This is the interface we'll be dealing with.
  IProgressObserver = interface(IInterface)
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
  end;

  // This will help us anonymously create implementations of the IProgressObserver
  // interface.
  TAnonymousObserverImp = class(TInterfacedObject, IProgressObserver)
  type
    // Declare reference types for all the methods the interface needs.
    TReportProgressProc = reference to procedure(Progress:Integer);
    TReportErrorProc = reference to procedure(Message:string);
  strict private
    FReportProgressProc: TReportProgressProc;
    FReportErrorProc: TReportErrorProc;

    // Actual implementation of interface methods.
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
    // private constructor, so we'll forced to use the public "Construct" function
    constructor Create(aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc);
  public
    // This takes the required anonymous methods as parameters and constructs an anonymous implementation
    // of the IProgressObserver interface.
    class function Construct(aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc): IProgressObserver;
  end;

{ TAnonymousObserverImp }

class function TAnonymousObserverImp.Construct(
  aReportProgressProc: TReportProgressProc;
  aReportErrorProc: TReportErrorProc): IProgressObserver;
begin
  // Call the private constructor
  Result := TAnonymousObserverImp.Create(aReportProgressProc, aReportErrorProc);
end;

constructor TAnonymousObserverImp.Create(
  aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc);
begin
  inherited Create;
  // We simply save the references for later use
  FReportProgressProc := aReportProgressProc;
  FReportErrorProc := aReportErrorProc;
end;

procedure TAnonymousObserverImp.ReportError(Message: string);
begin
  // Delegate to anonymous method
  FReportErrorProc(Message);
end;

procedure TAnonymousObserverImp.ReportProgress(Progress: Integer);
begin
  // Delegate to anonymous method
  FReportProgressProc(Progress);
end;

一旦所有代码都到位了,你就可以编写像这样的代码:

var i: IProgressObserver;
begin
  i := TAnonymousObserverImp.Construct(
    procedure (Progress:Integer)
    begin
      // Do something with Progress
    end
    ,
    procedure (Message:string)
    begin
      // Do something with Message
    end
  )
end;

我觉得看起来非常匿名!鉴于Delphi中匿名方法的实现方式,它也相当快速有效。


哇!太棒了(假设它能正常工作……我还没有测试过)。当然,如果您只创建一个实例,那么代码会更多(而我只是创建一个实例)。在我的情况下,只需创建一个命名类就容易得多,但如果您正在编写数百万程序员使用的第三方库,这将是可行的方法。我想知道所有这些样板代码是否可以自动生成? - awmross
2
@awmross,当然可以运行,我在发布之前会测试我的代码!自动化生成样板不应该是太大的问题,但如果编译器能做到就更好了。 - Cosmin Prund
虽然这确实很聪明,但我很难看出这在什么时候会特别有用。 - David Heffernan
1
@David,我正在使用类似这样的东西来实现枚举器,它非常方便。VCL本身在TDelegatedComparer<T>中也是这样做的,我相信还有其他的例子。 - Cosmin Prund
2
@David,对于像OP示例这样的小接口,有些痛苦:您需要声明一个类和一些方法+实现,而且所有这些都不能局部于实际需要接口实例的过程。使用此类匿名实现可将实现保留在逻辑上所需的位置,并且不会污染命名空间。我再次给出TDelegatedComparer<T>的示例:我真的讨厌预泛型TList.Sort()调用所需的全局函数! - Cosmin Prund
显示剩余6条评论

6

很抱歉,Delphi没有匿名类。


1
Prism不是Delphi。 - Jason Southwell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接