Man muss sich einfach darüber klar sein, dass ein Interface ganz bewusst nichts Konkretes ist, sondern lediglich eine Zusicherung. Das bedeutet, der Benutzer (im Sinne einer Klasse) des Interfaces muss die konkrete Implementation überhaupt nicht kennen, kann sich aber trotzdem sicher sein, dass alle im Interface deklarierten Properties und Methoden vorhanden sind. Dadurch wird eine einfache Erweiterbarkeit erreicht. Ein kleines Beispiel: nehmen wir an, wir haben die Klassen TDings und TConsumer. Letztere ruft eine Methode Blubb der Ersteren auf.
Delphi-Quellcode:
type
TDings =
class
public
procedure Blubb;
end;
TConsumer =
class
public
procedure Wuppdi(
const Dings: TDings);
end;
...
procedure TConsumer.Wuppdi(
const Dings: TDings);
begin
Dings.Blubb;
end;
Alles cool, alles easy. Nun wollen wir das Programm erweitern und schreiben eine Klasse TBums, die ebenfalls eine Methode Blubb enthält. Die Consumer-Klasse soll sowohl mit TDings als auch mit TBums umgehen können. Was können wir tun? Mir fallen da ein paar Möglichkeiten ein:
- Überladen der
Wuppdi-Methode
- Ableiten der TDings- und TBums-Klasse von einer gemeinsamen Elternklasse, die Blubb als (ggf. virtuelle oder dynamische) Methode einführt. Das macht dann eine Änderung des Parametertyps in den Typ der Elternklasse notwendig.
- Ändern des Parametertyps in TObject und Abfrage in der Methode, ob es sich um TDings oder TBums handelt, dann Typecast und Aufruf.
Das ist alles nicht so wirklich elegant und macht Änderungen an verschiedenen Stellen nötig. Hier kommen jetzt die Interfaces ins Spiel: man ändert einmalig den Parametertyp in einen Interfacetyp, in dem die Blubb-Methode vereinbart wird. TDings und TBums implementieren jetzt dieses Interface, TConsumer greift dann darüber auf die Methode zu. Soll später eine weitere Klasse TSchiessMichTot dazukommen, lässt man sie ebenfalls das Interface implementieren, schon kann TConsumer ohne jede Codeänderung auch damit umgehen.
Delphi-Quellcode:
type
ISuperIntf = interface
['{01107754-046D-4A32-AC6F-D96BC2AECCE0}']
procedure Blubb;
end;
TDings = class(TInterfacedObject, ISuperIntf)
public
procedure Blubb;
end;
TBums = class(TInterfacedObject, ISuperIntf)
public
procedure Blubb;
end;
...
procedure TConsumer.Wuppdi(const SuperIntf: ISuperIntf);
begin
SuperIntf.Blubb;
end;