在Delphi中使用接口的优缺点是什么?

Gui*_*ens 28 delphi interface

我已经使用Delphi类了一段时间但从未真正使用过接口.我已经读过一些关于它们的内容,但想了解更多.

我想知道在Delphi中使用接口时遇到的关于编码,性能,可维护性,代码清晰度,层分离以及一般来说您可以想到的任何方面的优缺点.

谢谢和最好的问候

jpf*_*ius 26

我现在能想到的一切:

优点:

  • 界面和实现之间的明确分离
  • 减少单位依赖性
  • 多重继承
  • 引用计数(如果需要,可以禁用)

缺点:

  • 类和接口引用不能混合(至少与引用计数有关)
  • 所有属性都需要getter和setter函数
  • 引用计数不适用于循环引用
  • 调试困难(感谢gabr和Warren指出这一点)

  • 调试接口对我来说相当困难.在包括XE在内的大多数Delphi版本中,单步调用接口调用对我来说并不干净.当大量使用接口时,检查和理解应用程序变得更加困难.在许多接口很多的应用程序中,修复内存泄漏对我来说几乎是不可能的. (4认同)
  • 好清单.我只会添加Cons - 调试接口问题(引用没有递减/过早递减 - 或者在翻译中 - 内存未被释放/内存过早发布)可能是非常混乱的业务. (3认同)
  • 在某些情况下,可能会增加使用接口的(小)性能损失.但总的来说,Delphi本机接口(而不是COM)实现非常快速和优化(与虚拟方法一样快,加上一些引用计数). (3认同)
  • @Dangph只是不继承自`TInterfacedObject`,而是自己实现`IInterface`中的方法,并始终返回-1作为引用计数.如果您需要更多详细信息,请将此问题作为单独的问题. (2认同)

Bha*_*rat 12

增加答案的几个优点:

  1. 使用接口来表示行为,并且每个行为的实现都将实现该接口.
  2. API发布:接口在发布API时非常有用.您可以在不给出实际实现的情况下发布接口.因此,您可以自由地进行内部结构更改,而不会给客户带来任何问题.

  • @Eugene:那COM怎么样也死了?事实上,我不是只谈论COM/Activex. (4认同)
  • @Eugene:你提到了组件/库,但Bharat却没有.应用程序的API是一个完全相同的API,接口非常适合它.对答案的投票似乎完全不公平. (2认同)

Dan*_*iel 10

我所说的是,在我的delphi的愿望清单中,没有引用计数的接口非常高!

- >接口的真正用途是接口的声明.不是引用计数的能力!

  • 在任何人告诉我在_AddRef/_Release中返回-1之前:不,这不是我的意思.我的意思是delphi甚至不会调用这些方法的接口! (5认同)
  • 这些方法调用究竟出了什么问题,实际上非常简单.原因是进行了接口清理:创建一个对象,将其作为接口引用传递给方法,再次删除它,保留当前方法 - >访问冲突,因为在已经销毁的对象上调用_Release. (2认同)

War*_* P 7

接口有一些SUBTLE缺点我不知道人们在使用它们时会考虑:

  1. 调试变得更加困难.我在调试器中看到了很多进入接口方法调用的奇怪困难.

  2. Delphi中的接口带有IUnknown语义,如果你喜欢或不喜欢,你坚持使用引用计数作为支持的接口.因此,对于在Delphi世界中创建的任何接口,您必须确保正确处理引用计数,如果不这样做,则最终会出现泄漏.当你想避免引用计数时,你唯一的选择是覆盖addref/decref并且实际上不释放任何东西,但这并非没有它自己的问题.我发现负载较多的接口代码库有一些最难以发现的访问冲突和内存泄漏,我认为这是因为将refcount语义和默认的delphi语义(所有者)结合起来非常困难.释放物品,没有其他人可以做,大多数物品都是在父母的整个生命中生活的.)

  3. 使用Interfaces做得不好的实现可能会产生一些讨厌的代码气味.例如,在定义类的初始具体实现的同一单元中定义的接口,添加接口的所有权重,而不实际在接口的用户和实现者之间提供适当的分离.我知道这不是接口本身的问题,而是对编写基于接口的代码的人更多的狡辩.请将您的接口声明放在仅包含这些接口声明的单元中,并避免因将接口声明重命名为与实现者类相同的单元而导致的单元到单元依赖性地狱.


Dav*_*nan 5

当我希望具有不同祖先的对象提供公共服务时,我主要使用接口.根据我自己的经验,我能想到的最好的例子是一个名为IClipboard:

IClipboard = interface
  function CopyAvailable: Boolean;
  function PasteAvailable(const Value: string): Boolean;
  function CutAvailable: Boolean;
  function SelectAllAvailable: Boolean;
  procedure Copy;
  procedure Paste(const Value: string);
  procedure Cut;
  procedure SelectAll;
end;
Run Code Online (Sandbox Code Playgroud)

我有一堆从标准VCL控件派生的自定义控件.他们每个都实现这个接口.当剪贴板操作到达我的一个表单时,它会查看活动控件是否支持此接口,如果是,则调度适当的方法.

对于一个非常简单的接口,您可以使用of object事件处理程序执行此操作,但一旦它变得足够复杂,接口就可以正常工作.事实上,我认为这是一个非常好的模拟.使用您单个of object事件不适合该功能的界面.