【问题标题】:Delphi - Interfaces inside interfacesDelphi - 接口内的接口
【发布时间】:2015-11-06 03:39:21
【问题描述】:

我是接口方面的新手。我google了很多,但我不知道在以下情况下该怎么办。

我创建了多个接口,它们相互使用:

IPart = interface(IInterface)
  Function getName: string;
  procedure setName(aValue: string)
  property Name: string read getName write setname;
end;


IOfferLine= interface(iInterface)
  Function getPart: IPart;
  function getAmount: double;
  procedure setPart(aPart: IPart);
  procedure setAmount(value: double);
  property Amount: double read getAmount write setAmount;
  property Part: IPart read GetPart write setPart;
end;

IOffer= interface(iInterface)
  function getOffLines: tList<IOfferline>;
  procedure setOffLines(aList: tList<IOfferline>);
  property OffLines: tList<IOfferlines> read getOffLines write setOfflines;
end;

现在我想实现这些接口。

TPart = class(TInterfacedObject, IPart)
  private
    _Name: string;
    function getName: string;
    procedure setName(aValue: string);
  public
    property Name: string read getName write setName;
end;

TOfferLine = class(TInterfacedObject, IOfferLine)
  private
    _amount: double;
    _part: TPart;
    function getAmount: double;
    function getPart: tPart;
    procedure setAmount(aValue: double);
    procedure setPart(aPart: TPart);
  public
    property Amount: double read getAmount write setAmount;
    property Part: TPart read GetPart write SetPart;
  end;

TOffer = class(TInterfacedObject, IOffer)
  private
    _OfferLines: tList<TOfferline>;
    function getOffLines: tList<tOfferline>;
    procedure setOffLines(aList: tList<tOfferline>);
  public
    property offLines: tList<TOfferline> read getOffLines write setOffLines;
end;

我已经添加了实现。

function TOfferLine.getPart: tPart;
begin
  result := _part;
end;

但我仍然得到“缺少接口方法 IOfferline.GetPart 的实现;”

我不知道为什么。

【问题讨论】:

  • 您显示的代码无法编译并且相当混乱。这表明缺乏清晰度和对细节的关注。这里也没有明确和直接的问题。我认为您可能需要更加专注地重新编写这个问题。
  • @DavidHeffernan,我编辑了这个问题。你能解释一下为什么这段代码很乱吗?
  • 代码仍然无法编译。它仍然以难以阅读的方式缩进。仍然没有具体的问题。看起来你在走路之前就想跑。
  • 所有类型声明中都缺少 end 关键字。
  • 当然……你在接口中的GetPart是IPart而不是TPart!!

标签: delphi interface interface-implementation


【解决方案1】:

我不知道您要做什么,但如果您没有编写如此凌乱的代码,那么它会更容易阅读。但是感谢上帝,我们有一个源格式化程序。

你的代码有几个问题:

First 你的属性被声明为property OffLines: TList&lt;IOfferline**s**&gt;,而你的接口被命名为IOfferline

然后TOfferline 你有一个方法procedure setPart(aPart: TPart); 应该是过程 setPart(aPart: IPart);因为这就是您声明界面的方式。而你使用 TPart 的所有其他地方都应该是 IPart。

TOffer 也是如此

这是您的代码的清理版本:

unit Unit20;

interface
uses
  Generics.Collections;

type
  IPart = interface(IInterface)
    function getName: string;
    procedure setName(aValue: string);
    property Name: string read getName write setName;
  end;

  IOfferLine = interface(IInterface)
    function getPart: IPart;
    function getAmount: double;
    procedure setPart(aPart: IPart);
    procedure setAmount(value: double);
    property Amount: double read getAmount write setAmount;
    property Part: IPart read getPart write setPart;
  end;

  IOffer = interface(IInterface)
    function getOffLines: TList<IOfferLine>;
    procedure setOffLines(aList: TList<IOfferLine>);
    property OffLines: TList < IOfferLine > read getOffLines write setOffLines;
  end;

  TPart = class(TInterfacedObject, IPart)
  private
    _Name: string;
    function getName: string;
    procedure setName(aValue: string);
  public
    property Name: string read getName write setName;
  end;

  TOfferline = class(TInterfacedObject, IOfferLine)
  private
    _amount: double;
    _part: TPart;
    function getAmount: double;
    function getPart: IPart;
    procedure setAmount(aValue: double);
    procedure setPart(aPart: IPart);
  public
    property Amount: double read getAmount write setAmount;
    property Part: IPart read getPart write setPart;
  end;

  TOffer = class(TInterfacedObject, IOffer)
  private
    _OfferLines: TList<TOfferline>;
    function getOffLines: TList<IOfferLine>;
    procedure setOffLines(aList: TList<IOfferLine>);
  public
    property OffLines: TList < IOfferLine > read getOffLines write setOffLines;
  end;

implementation

{ TOfferline }

function TOfferline.getAmount: double;
begin

end;

function TOfferline.getPart: IPart;
begin

end;

procedure TOfferline.setAmount(aValue: double);
begin

end;

procedure TOfferline.setPart(aPart: IPart);
begin

end;

{ TOffer }

function TOffer.getOffLines: TList<IOfferLine>;
begin

end;

procedure TOffer.setOffLines(aList: TList<IOfferLine>);
begin

end;

{ TPart }

function TPart.getName: string;
begin

end;

procedure TPart.setName(aValue: string);
begin

end;

end.

【讨论】:

  • 顺便说一句.. 没有必要在实现类中定义属性,因为它们无论如何都会通过接口引用。实现 getter 和 setter 就足够了。 Delphi 足够聪明,可以在接口变量的自动完成中只显示属性。
  • 你是绝对正确的。我没有查看代码,我只是编译了它:p
  • @ZENsan - 这取决于您的属性是否通过接口专门引用。例如如果您的接口类是基类,则必须使用 get/set 方法来引用派生类实现中的继承属性可能会很烦人。
【解决方案2】:

编译器说缺少实现的原因仅仅是因为缺少实现。

IOfferLine 的接口声明了这个 getPart 方法:

IOfferLine= interface(iInterface)
  ..
  function getPart: IPart;
  ..
end;

但是你的实现类没有提供这个方法。您的类中的 getPart 方法被实现为返回 object 引用,而不是 interface 引用:

TOfferLine = class(TInterfacedObject, IOfferLine)
private
  ..
  function getPart: tPart;
  ..
end;

您需要确保您的实现类确实准确且准确地提供了它实现的接口所需的成员:

TOfferLine = class(TInterfacedObject, IOfferLine)
private
  ..
  function getPart: IPart;
  ..
end;

function TOfferline.getPart: IPart;
begin
  result := _part as IPart;
end;

但是,由于对 OfferLine 对象(在 _part 变量中)维护的 Part 的引用是对象引用,因此引用使用接口(通过 getPart: IPart 方法)获得的对象可能会导致该 Part 对象被销毁,因为 OfferLine 中的对象引用是不计算在内(字面意思)。

您当然可以通过将 OfferLine 持有的 Part 引用作为接口引用本身来避免这种情况,但是如果没有完整的图片,很难说这是否有效整个对象模型。如果您的对象的生命周期是由问题中不明显的其他机制确保的,那么这可能不是问题,但如果到目前为止还没有特别考虑过,那么它可能确实需要解决。

虽然可以安全地进行操作,但作为一般规则,将对象引用和对同一对象的接口引用混合会导致问题。

【讨论】:

    猜你喜欢
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 2014-02-27
    • 2013-04-19
    • 1970-01-01
    • 2011-10-01
    • 2020-12-27
    • 2011-01-28
    相关资源
    最近更新 更多