简体   繁体   English

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

[英]What are the pros and cons of using interfaces in Delphi?

I have used Delphi classes for a while now but never really got into using interfaces. 我已经使用Delphi类了一段时间但从未真正使用过接口。 I already have read a bit about them but want to learn more. 我已经读过一些关于它们的内容,但想了解更多。

I would like to hear which pros and cons you have encountered when using interfaces in Delphi regarding coding, performance, maintainability, code clearness, layer separation and generally speaking any regard you can think of. 我想知道在Delphi中使用接口时遇到的关于编码,性能,可维护性,代码清晰度,层分离以及一般来说您可以想到的任何方面的优缺点。

Thanks and best regards 谢谢和最好的问候

All I can think of for now: 我现在能想到的一切:

Pros: 优点:

  • Clear separation between interface and implementation 界面和实现之间的明确分离
  • Reduced unit dependencies 减少单位依赖性
  • Multiple inheritance 多重继承
  • Reference counting (if desired, can be disabled) 引用计数(如果需要,可以禁用)

Cons: 缺点:

  • Class and interface references cannot be mixed (at least with reference counting) 类和接口引用不能混合(至少与引用计数有关)
  • Getter and setter functions required for all properties 所有属性都需要getter和setter函数
  • Reference counting does not work with circular references 引用计数不适用于循环引用
  • Debugging difficulties (thanks to gabr and Warren for pointing that out) 调试困难(感谢gabr和Warren指出这一点)

Adding to the answers few more advantages: 增加答案的几个优点:

  1. Use interfaces to represent the behavior and each implementation of a behavior will implement the interface. 使用接口来表示行为,并且每个行为的实现都将实现该接口。
  2. API Publishing: Interfaces are great to use when publishing APIs. API发布:接口在发布API时非常有用。 You can publishing an interface without giving out the actual implementation. 您可以在不给出实际实现的情况下发布接口。 So you are free to make internal structural changes without causing any problems to the clients. 因此,您可以自由地进行内部结构更改,而不会给客户带来任何问题。

All I say is that interfaces WITHOUT reference counting are VERY HIGH on my wishlist for delphi!!! 我所说的只是在我的delphi的愿望清单上没有引用计数的接口非常高!

--> The real use of interfaces is the declaration of an interface. - >接口的真正用途是接口的声明。 Not the ability for reference counting! 不是引用计数的能力!

There are some SUBTLE downsides to interfaces that I don't know if people consider when using them: 接口有一些SUBTLE缺点我不知道人们在使用它们时会考虑:

  1. Debugging becomes more difficult. 调试变得更加困难。 I have seen a lot of strange difficulties stepping into interfaced method calls, in the debugger. 我在调试器中看到了很多进入接口方法调用的奇怪困难。

  2. Interfaces in Delphi come with IUnknown semantics, if you like it or not, you'r stuck with reference counting being a supported interface. Delphi中的接口带有IUnknown语义,如果你喜欢或不喜欢,你坚持使用引用计数作为支持的接口。 And, thus, with any interfaces created in Delphi's world, you have to be sure you handle reference counting correctly, and if you don't, you'll end up with leaks. 因此,对于在Delphi世界中创建的任何接口,您必须确保正确处理引用计数,如果不这样做,则最终会出现泄漏。 When you want to avoid reference counting, your only choice is to override addref/decref and don't actually free anything, but this is not without its own problems. 当你想避免引用计数时,你唯一的选择是覆盖addref / decref并且实际上不释放任何东西,但这并非没有它自己的问题。 I find that the more heavily interface-laden codebases have some of the hardest-to-find access violations, and memory leaks, and this is, I think because it is very difficult to combine the refcount semantics, and the default delphi semantics (owner frees objects, and nobody else does, and most objects live for the entire life of their parents.). 我发现负载较多的接口代码库有一些最难以发现的访问冲突和内存泄漏,我认为这是因为将refcount语义和默认的delphi语义(所有者)结合起来非常困难。释放物品,没有其他人这样做,大多数物品都是在父母的整个生命中生活的。)

  3. Badly-done implementations using Interfaces can contribute some nasty code-smells. 使用Interfaces做得不好的实现可能会产生一些讨厌的代码气味。 For example, Interfaces defined in the same unit that defines the initial concrete implementation of a class, add all the weight of interfaces, without really providing proper separation between the users of the interfaces and the implementors. 例如,在定义类的初始具体实现的同一单元中定义的接口,添加接口的所有权重,而不真正提供接口的用户和实现者之间的适当分离。 I know this isn't a problem with interfaces themselves, but more of a quibble with those who write interface-based code. 我知道这不是接口本身的问题,而是对编写基于接口的代码的人更多的狡辩。 Please put your interface declarations in units that only have those interface declarations in them, and avoid unit-to-unit dependency hell caused by glomming your interface declarations into the same units as your implementor classes. 请将您的接口声明放在仅包含这些接口声明的单元中,并避免因将接口声明重命名为与实现者类相同的单元而导致的单元到单元依赖性地狱。

I mostly use interfaces when I want objects with different ancestry to offer a common service. 当我希望具有不同祖先的对象提供公共服务时,我主要使用接口。 The best example I can think of from my own experience is an interface called IClipboard : 根据我自己的经验,我能想到的最好的例子是一个名为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;

I have a bunch of custom controls derived from standard VCL controls. 我有一堆从标准VCL控件派生的自定义控件。 They each implement this interface. 他们每个都实现这个接口。 When a clipboard operation reaches one of my forms it looks to see if the active control supports this interface and, if so, dispatches the appropriate method. 当剪贴板操作到达我的一个表单时,它会查看活动控件是否支持此接口,如果是,则调度相应的方法。

For a very simple interface you can do this with an of object event handler, but once it gets sufficiently complex an interface works well. 对于一个非常简单的接口,您可以使用of object事件处理程序执行此操作,但是一旦它变得足够复杂,接口就可以正常工作。 In fact I think that is a very good analogue. 事实上,我认为这是一个非常好的模拟。 Use an interface where you a single of object event won't fit the functionality. 使用一个of object事件不适合该功能的接口。

Interfaces solves a certain kind of issues. 接口解决了某种问题。 The primary function is to... well, ...define interfaces. 主要功能是......好吧,...定义接口。 To distinguish between definition and implementation. 区分定义和实现。

When you want to specify or check if a class supports a set of methods - use interfaces. 如果要指定或检查类是否支持一组方法 - 请使用接口。

You cannot do that in any other way. 你不能以任何其他方式做到这一点。

(If all classes inherits from the same base class, then an abstract class will define the interface. But when you are dealing with different class hierarchies, you need interfaces to define the methods thy have in common...) (如果所有类都继承自相同的基类,那么抽象类将定义接口。但是当您处理不同的类层次结构时,您需要接口来定义您共有的方法...)

Extra note on Cons: Performance 关于缺点:绩效的额外说明

I think many people are too blithely dismissing the performance penalty of interfaces. 我想很多人都过于宽容地忽视接口的性能损失。 (Not that I don't like and use interfaces but you should be aware of what you are getting into). (不是我不喜欢和使用接口,但你应该知道你正在进入什么)。 Interfaces can be expensive not just for the _AddRef / _Release hit (even if you are just returning -1) but also that properties are REQUIRED to have a Get method. 接口可能很昂贵,不仅仅是_AddRef / _Release命中(即使你只是返回-1),而且属性也需要有一个Get方法。 In my experience, most properties in a class have direct access for the read accessor (eg, propery Prop1: Integer read FProp1 write SetProp1). 根据我的经验,类中的大多数属性都可以直接访问读取访问器(例如,属性Prop1:整数读取FProp1写入SetProp1)。 Changing that direct, no penalty access to a function call can be significant hit on your speed (especially when you start adding 10s of property calls inside a loop. 直接更改,不会对函数调用进行惩罚访问会对您的速度产生重大影响(特别是当您开始在循环内添加10个属性调用时)。

For example, a simple loop using a class 例如,使用类的简单循环

for i := 0 to 99 do
begin
  j := (MyClass.Prop1 + MyClass.Prop2 + MyClass.Prop3) / MyClass.Prop4;
  MyClass.Update;
  // do something with j
end;

goes from 0 function calls to 400 function calls when the class becomes an interface. 当类成为接口时,从0函数调用到400函数调用。 Add more properties in that loop and it quickly gets worse. 在该循环中添加更多属性,它会很快变得更糟。

The _AddRef / _Release penalty you can ameliorate with some tips (I am sure there are other tips. This is off the top of my head): _AddRef / _Release惩罚你可以改进一些提示(我相信还有其他的提示。这是我的头脑):

  • Use WITH or assign to a temp variable to only incur the penalty of one _AddRef / _Release per code block 使用WITH或赋值给temp变量只会对每个代码块产生一个_AddRef / _Release的惩罚
  • Always pass interfaces using const keyword into a function (otherwise, you get an extra _AddRef / _Release occurs every time that function is called. 始终使用const关键字将接口传递给函数(否则,每次调用该函数时都会发生额外的_AddRef / _Release。

The only case when we had to use interfaces (besides COM/ActiveX stuff) was when we needed multiple inheritance and interfaces were the only way to get it. 我们必须使用接口(除了COM / ActiveX之外)的唯一情况是当我们需要多继承时,接口是获得它的唯一方法。 In several other cases when we attempted to use interfaces, we had various kinds of problems, mainly with reference counting (when the object was accessed both as a class instance and via interface). 在我们尝试使用接口的其他几种情况下,我们遇到了各种各样的问题,主要是引用计数(当对象作为类实例和通过接口访问时)。

So my advice would be to use them only when you know that you need them, not when you think that it can make your life easier in some aspect. 所以我的建议是只有当你知道自己需要它们时才使用它们,而不是当你认为它可以让你的生活在某些方面变得更容易时。

Update: As David reminded, with interfaces you get multiple inheritance of interfaces only, not of implementation. 更新:正如大卫提醒的那样,通过接口,您只能获得多个接口继承,而不是实现。 But that was fine for our needs. 但这对我们的需求来说很好。

Beyond what others already listed, a big pro of interfaces is the ability of aggregating them. 除了其他已经列出的内容之外,接口的一个重要功能是聚合它们的能力。

I wrote a blog post on that topic a while ago which can be found here: http://www.nexusdb.com/support/index.php?q=intf-aggregation (tl;dr: you can have multiple objects each implementing an interface and then assemble them into an aggregate which to the outside world looks like a single object implementing all these interfaces) 我刚才写了一篇关于该主题的博客文章,可以在这里找到: http//www.nexusdb.com/support/index.php? q = intf -aggregation(tl; dr:你可以有多个对象,每个实现一个接口,然后将它们组装成一个聚合,对外部世界看起来像一个实现所有这些接口的对象)

You might also want to have a look at the "Interface Fundamentals" and "Advanced Interface Usage and Patterns" posts linked there. 您可能还想查看那里链接的“界面基础”和“高级界面使用和模式”帖子。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Delphi Prism 2010/2011的优点/缺点是什么? - What are the pros/cons of Delphi Prism 2010/2011? 使用动态数组记录与TList的优缺点是什么? <TMyRecord> 在德尔福? - What are the pros and cons of using dynamic array of records vs. TList<TMyRecord> in Delphi? RemObjects PascalScript 与 DWS 脚本的优缺点是什么? - What are the pros and cons of RemObjects PascalScript versus the DWS script? 在Delphi中定义记录 - (记录为类型vs记录为变量) - 差异,缺点和优点......? - Defining records in Delphi - (Record as type vs Record as variable) - Differences, cons and pros..? Delphi 3支持接口中的等效功能是什么? - What's the equivalent in Delphi 3 of Supports for Interfaces? Delphi - 使用来自另一个单元的接口 - Delphi - Using interfaces from another unit 比较 2 个接口(IControl)的好方法是什么? 这是 Delphi 中的错误吗? - What is a good way to compare 2 interfaces (IControl)? Is this a bug in Delphi? 在Delphi和Lazarus(FPC)中实现接口有什么区别? - What are the differences between implementation of Interfaces in Delphi and Lazarus (FPC)? Delphi匿名方法 - 赞成和利弊。 在Delphi中使用闭包(anonymus方法)时的良好实践 - Delphi anonymous methods - pro and cons. Good practices when using closures(anonymus methods) in Delphi 以多线程方式使用Delphi7 COM接口时的内存消耗 - Memory consumption when using Delphi7 COM interfaces in a multithreaded way
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM