如何在不重新实现方法的情况下从外部接口继承接口

Posted

技术标签:

【中文标题】如何在不重新实现方法的情况下从外部接口继承接口【英文标题】:How to inherit a Interface from foreign Interface without reimplementing the Methods 【发布时间】:2021-11-16 01:44:48 【问题描述】:

我想创建一个接口对象,它支持来自其他地方的接口 + 我自己的函数。那么,如何堆叠/聚合/增强接口?我想这是可能的,但我找不到专门用于我的继承实验的 sn-p 或演示。

这个解决方案不是我想要的:

TImplement = Class(TInterfacedObject, IOne, ITwo)
private
  FOne: IOne;
public
  property One: IOne read FOne implements IOne;
  property Two: ITwo read FTwo implements ITwo;
end;

当前使用情况:

(MyInterface as IOne).Something;
(MyInterface as ITwo).SomethingElse;

所需用途:

MyInterface.Something;
MyInterface.SomethingElse;

我尝试继承接口:

ITogether = Interface(IOne)
  procedure SomeThingElse;
end:

TImplement = Class(TInterfacedObject, ITogether)
// or Class(TInterfacedObject, ITogether, IOne) => Both result in missing Implementation message on compile ... 
private
  FOne: IOne;
  function SomeThingElse;
public
  property One: IOne read FOne implements IOne;
end;

这个组合的意思是:

E2291 接口 IOne 中方法 x 的实现缺失。

是否可以以某种方式组合接口,以便可以进行“无强制转换”调用?

编辑: Rob Lambden 的回答对我来说是缺失的信息。 Uwe Raabes 答案是正确的实现。 (可能是唯一可能的) 所以 uwe 赢得了答案,我只能投票给 Rob 的答案。

【问题讨论】:

【参考方案1】:

您可以实现 IOne 方法并将它们转发到 FOne 接口。

type
  IOne = interface
    ['19F785C0-5D2E-479F-BB2C-88A00BA4C812']
    procedure Something;
  end;

  ITogether = interface(IOne)
    ['B8B7F690-DC98-41AB-A6D9-29F70330EDA5']
    procedure SomethingElse;
  end;

type
  TTogether = class(TInterfacedObject, ITogether)
  private
    FOne: IOne;
  protected
    property One: IOne read FOne;
  public
    constructor Create(AOne: IOne);
    procedure SomethingElse;
    procedure Something;
  end;

constructor TTogether.Create(AOne: IOne);
begin
  inherited Create;
  FOne := AOne;
end;

procedure TTogether.Something;
begin
  One.Something;
end;

procedure TTogether.SomethingElse;
begin
   Do something else 
end;

AFAIK,当 implementor 是接口属性时,没有像 implements 这样的语言结构可以为您做到这一点。

更新: 如果您有多种情况需要扩展 IOne 接口,则可以编写一个包装类,该类反过来适合 implements 关键字。

type
  TOneWrapper = class
  private
    FOne: IOne;
  protected
    property One: IOne read FOne;
  public
    constructor Create(AOne: IOne);
    procedure Something;
  end;

type
  TTogether = class(TInterfacedObject, ITogether)
  private
    FOne: TOneWrapper;
  protected
    property One: TOneWrapper read FOne implements ITogether;
  public
    constructor Create(AOne: IOne);
    destructor Destroy; override;
    procedure SomethingElse;
  end;

constructor TTogether.Create(AOne: IOne);
begin
  inherited Create;
  FOne := TOneWrapper.Create(AOne);
end;

destructor TTogether.Destroy;
begin
  FOne.Free;
  inherited Destroy;
end;

procedure TTogether.SomethingElse;
begin
   Do something else 
end;

constructor TOneWrapper.Create(AOne: IOne);
begin
  inherited Create;
  FOne := AOne;
end;

procedure TOneWrapper.Something;
begin
  One.Something;
end;

【讨论】:

是的,这是一个可能的解决方案。我的“外国”界面有大约 80 个元素。而且我不想对我进行维护。 维护可以减少为方法签名的更改以及新的或删除的方法。两者都是通过编译找到的。 当需要对基本接口进行多个扩展时,我添加了一种减少编码的方法。 @UweRaabe “接口属性”恕我直言有点用词不当。如果您将一个属性声明为接口的一部分,然后创建一个实现该接口的对象,则该属性不是对象的一部分,除非它被重新声明(因此您可以通过接口引用而不是通过对象引用访问该属性)。访问器方法在那里,但不是属性。对我来说似乎很奇怪...... @RobLambden,带有“接口属性”,我在这里指的是某些“接口”类型的属性。【参考方案2】:

您的问题似乎与两件事有关。首先是关于调用方法而不必强制转换。

只需使用对象引用,您就可以做到这一点。

  MyObject:=TImplements.Create;
  MyObject.Something;
  MyObject.SomethingElse;

其次,它是关于实现接口而无需重新实现功能。

根据定义,Delphi 接口不能包含实现。 (这些方法必须是抽象的,或者用 C++ 术语来说它们是“纯虚拟的”)。

这意味着您不能像使用 C++ 那样实现多继承类型。任何实现接口的对象都必须实现所有实现功能...或...

可以将接口委托给您的示例中的属性,如果您这样做,如果您使用对象引用,您仍然可以调用方法而无需强制转换。

【讨论】:

好的,谢谢。这回答了我的问题。摘要:“如果不重新实现方法,delphi 就不能从接口调用函数。从对象引用它是可能的。”这回答了我的问题并结束了我的实验。我只是想替换现有代码中的接口。但我明白了:我必须在需要的地方对我的新附加功能进行类型转换。 我注意到你已经说过这回答了你的问题......但你没有选择它作为答案。如果我可以改进答案,请提出建议,以便我可以更好地帮助其他人。 是的,我知道...您对为什么我不能在不重新实现的情况下继承接口的答案是缺少信息来结束我对所需解决方案的搜索。如果可以的话,我会将两个答案合二为一……然后给你们两个答案。 (我试过了,没用)

以上是关于如何在不重新实现方法的情况下从外部接口继承接口的主要内容,如果未能解决你的问题,请参考以下文章

如何在不破坏内部绑定的情况下从外部初始化自定义项的属性?

如何在不使用表单的情况下从 Rails 应用程序发布到外部 url

如何在不重新保存的情况下从 iCloud 下载图像?

如何在不重新加载页面的情况下从 FF Web 扩展内容脚本更改 3rd 方网站上的 Angular 应用程序路由/URL

如何在不传递委托的情况下从 RootViewController 调用 AppDelegate 方法?

子组件如何在不监听生命周期方法的情况下从父组件接收 props?