They're one of the great secrets of the Delphi language. It allows you to separate DESIGN from IMPLEMENTATION.
I use interfaces mostly for the logical boundaries between program sections, though I also use them to wrap useful classes. If you look through my code, if it looks like I'm using a class, it's probably an interface instead.
Some big reasons off the top of my head:
1) Automatic lifetime management
2) Abstraction independent of class hierarchy (implementation)
3) Multiple interfaces PER CLASS -- you get the benefits of C++'s multiple inheritance without the nightmare.
Let's walk through these quickly:
(1) Automatic lifetime management
This means that the implementing class is freed automatically when all references to the interface are gone.
If you don't think this is any big deal, when's the last time you worked with strings? Could you imagine the huge PITA to have to allocate and free each and EVERY string? To not be able to simply use "+" to concatenate strings? I've lived that. No fun!
I feel the same way about having to allocate and free classes manually.
Compare:
//
// Example without interfaces
//
var
something :TSomething;
begin
something := TSomething.Create;
try
something.Whatever;
finally
something.Free;
end;
end;
vs.
//
// Example with interfaces
//
var
something :ISomething;
begin
something := TSomething.Create;
something.Whatever;
end;
(2) Abstraction independent of class hierarchy (implementation).
Classes simplify the messiness inherant in procedural programming.Interfaces simplify the messiness inherant in classes. You only deal with an abstraction, not an implementation.
There's more than one way to skin a cat. Imagine being able to skin cats, dogs, giraffes, and remote asteroids with the same tool. Welcome to the ability to HIDE IMPLEMENTATION. Yes, one can hide SOME implementation inside of classes, but classes themselves are still implementation. For the most part this is no big deal, but by the same token, programming without classes
is no big deal. What? You're too young to remember procedural programming?
*grin*
Programmers who think classes are no big deal, because they were raised on classes, do not understand the huge chasm between procedural and object-oriented programming. They claim to "understand" it, but they do not *know* it. When I talked with fellow programmers when we were making the transition from procedural to OO programming, we universally complained about the added complexity of classes, but saw that they could be useful in certain circumstances. (This is the same attitude Delphi programmers express about interfaces. "Useful for COM, but that's about it.") We didn't understand that the benefit from using classes far exceeded the massive amount of extra work involved in using classes. Do you really understand how much extra crap is involved with writing classes? No? Why do I manipulate classes with ModelMaker's Code Explorer (http://www.modelmakertools.com/ce.htm)?
My observation is that the power of this does not sink in until one is comfortable with interfaces, and one can freely design with each
complimenting the other.
This allows one to design very stable code, and removed the headache of massive changes because you had to alter a class hierarchy.
As an example, I referred to my database abstraction interfaces. One interface, with ANY NUMBER of database implementations underneath. Need to use NexusDB? Interbase? MySQL? ADO? Oracle? Each set of classes has its own
class hierarchy. They cannot be substituted one for another.
Any database code that I write uses the same two interfaces, ItcDatabase and ItcQuery. When I need to port to a different database, such as performance testing, preparing comparitive analyses, or whatever, I generally do not need alter my code much, if at all. All changes are due to SQL variances.
Now try ripping out entire class hierarchies and replace them with a completely different set of classes.
3) Multiple interfaces PER CLASS
Let's face it. If you've programmed for any length of time you get into those nasty class decisions where multiple inheritance would "be nice." Frequently it's not "just nice," but a correct design.
C++ has multiple inheritance, but if you're used it at any length, you've been burned. It comes with the territory. Because we can decouple DESIGN from IMPLEMENTATION with interfaces, we can get the bonuses without the pain.
I've already burned up too much time already; I'll let this one fall short.
. . . . . . .
I have to admit that I didn't understand interfaces until I prepared a session on COM programming for our local user group. I came back and said, "we need two sessions." The first was on interfaces only. The second on COM.I don't know that I will be able to explain any better than the other guys,but I'll give it a shot:
Interfaces is the Delphi alternative to multiple inheritance. A simple example is almost impossible, because interfaces are really a tool for dealing with design complexity. See if this makes sense:
Let's say, as an example, that you would like to customize a bunch of standard Delphi visual controls, to include field validation. You could create a descendent of each kind of form you want to enhance, and then when you finish editing, do something like:
FOR i := 0 TO Form1.ControlCount - 1 DO
IF Form1.Controls[i] IS TMyEditControl THEN
Ok := TMyEditControl(Form1.Controls[i]).ValidateMe
ELSE IF Form1.Controls[i] IS TMyCheckboxControl THEN
Ok := TMyCheckboxControl(Form1.Controls[i]).ValidateMe
ELSE IF Form1.Controls[i] IS TMyComboBox THEN
Ok := TMyComboBox(Form1.Controls[i]).ValidateMe
...and so on...
If, instead, you designed an interface that supported a "ValidateMe" procedure, you could support this interface in all your inherited controls,
a la:
IAutoValidate = Interface
FUNCTION ValidateMe : Boolean;
END;
Now, when you enhance a control, declare it thusly:
TMyEditControl = Class(TEdit, IAutoValidate)
PROCEDURE ValidateMe;
END;
Then you can have a generic "validator" routine that can handle any control, whether it supports your validator interface or not:
FUNCTION ValidatesOk( Ctl : TControl )
VAR
Ival : IAutoValidate;
BEGIN
IF Supports(IAutoValidate, Ctl, IVal) THEN
Result := IVal.ValidateMe
ELSE Result := True;
END;
Look what this gains you:
1. You have an absolutely generic way of handling special circumstances.
2. Interface "membership" is not evaluated until runtime. That means that you can have standard handling behavior for objects that may not even exist yet at compile time.
3. You can add the desired "interface" methods to any appropriate object without having to go re-craft case statements, as in the first example.
4. You can cluster related capabilities in a single interface.
5. You can define multiple interfaces for an object, cleaning up the design process considerably.
6. You can delegate interface methods to a separate object using the IMPLEMENTS keyword.
7. You can radically reduce the amount of superfluous code and code repetition in your programs.
The real trick to understanding interfaces is to know that an interface is really a contract--when an object implements an interface, it promises to provide specific implementations for every method defined in the interface. As a result, if an object supports a particular interface, you KNOW to a certainty that there are certain things you can do with that object, even if you know nothing else about it.
Anyway, in the right situation, interfaces are a tremendously effective tool. I hope this was helpful to somebody...