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

痴心易碎 提交于 2021-02-05 14:51:42

问题


I have used Delphi classes for a while now but never really got into using interfaces. 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.

Thanks and best regards


回答1:


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
  • Reference counting does not work with circular references
  • Debugging difficulties (thanks to gabr and Warren for pointing that out)



回答2:


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. 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.



回答3:


All I say is that interfaces WITHOUT reference counting are VERY HIGH on my wishlist for delphi!!!

--> The real use of interfaces is the declaration of an interface. Not the ability for reference counting!




回答4:


There are some SUBTLE downsides to interfaces that I don't know if people consider when using them:

  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. 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. 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. 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.).

  3. Badly-done implementations using Interfaces can contribute some nasty code-smells. 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.




回答5:


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 = 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. 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. 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.




回答6:


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...)




回答7:


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. In my experience, most properties in a class have direct access for the read accessor (e.g., propery Prop1: Integer read FProp1 write 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.

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. 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):

  • Use WITH or assign to a temp variable to only incur the penalty of one _AddRef / _Release per code block
  • Always pass interfaces using const keyword into a function (otherwise, you get an extra _AddRef / _Release occurs every time that function is called.



回答8:


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. 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.




回答9:


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)

You might also want to have a look at the "Interface Fundamentals" and "Advanced Interface Usage and Patterns" posts linked there.



来源:https://stackoverflow.com/questions/4861280/what-are-the-pros-and-cons-of-using-interfaces-in-delphi

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!