Berühmtestes Beispiel: IEnumerable<T>
Eigentlich müsste dieses Interface nur so aussehen:
Delphi-Quellcode:
type
IEnumerable<T> = interface
function GetEnumerator: IEnumerator<T>
end;
Und über
Extension Methodseinen interface helper kann man nun alle möglichen Operationen, die auf GetEnumerator operieren, implementieren.
Das ermöglicht einem eine Verkettung dieser Operationen -> syntax Sugar.
Anderes Beispiel:
Delphi-Quellcode:
type
ILogger = interface
procedure WriteLogEntry(const entry: TLogEntry);
end;
Simples Interface, wenn man neue Logger bauen will, muss man nur eine Methode implementieren -> gut!
Aber den Logger zu benutzen ist nun eher umständlich, denn es mag nun verschiedene Eigenschaften in TLogEntry geben, die ich immer befüllen muss.
Also würde sich so ein Interface helper anbieten:
Delphi-Quellcode:
type
ILoggerHelper = interface helper for ILogger
procedure LogValue<T>(const value: T)
procedure EnterMethod(const methodName: string);
procedure LeaveMethod(const methodName: string);
end;
In diesen Methoden wird nun nix anderes gemacht als die Information in ein TLogEntry gepackt und dann an die WriteLogEntry Methode übergeben.
D.h. ich kann die Funktionalität des Interfaces erweitern, ohne den Vertrag zu verletzen und ohne weitere Kopplung für den Implementierenden zu erzeugen.
Im Grunde sind so helper Methoden nix anderes als das:
procedure Methode(Self: <gehelpter type>; args)
Aber ein:
Delphi-Quellcode:
logger.EnterMethod('foo');
// liest sich einfach besser als:
EnterMethod(logger, 'foo');
Und umso mehr, wenn ich solche Methoden verketten kann (ja, das geht mit Spring4D aber auch nur, weil die ganzen Methoden auf IEnumerable<T> sitzen und somit dem Implementierer aufgezwungen werden, obwohl sie nur auf GetEnumerator aufsetzen -> fette Klassen):
Delphi-Quellcode:
for c in customers.Where(...).Ordered.Take(10) do
// mach was