Moin,
so ich geb auch mal meinen senf dazu
Schnitstellen (interfaces) sind nicht nur prima, um klassen irgendwie abstrakt zu definieren, sondern sind eine optimale entkopplungs-technick. Dh. man kann verschiedene systeme einer anwendung logisch trennen, sodass sie nur durch die schnittstelle verbunden sind - der name ist da eigentlich sehr sprechend. In delphi ist eigentlich das konzept der Events viel bekannter, was auch exessiv zur entkopplung eingesetzt wird, aber immer nur eine Information-liefern kann, da es nur eine methode definiert, was bei interfaces bekanntlich anders ist.
Ich setzt interfaces sehr gerne als
strategie ein, dh, ich übergebe einer klasse ein interface, worüber sie dann informationen beziehen oder aktionen ausführen kann, die sie eigentlich nix angehen und nicht in ihrem verantwortungsbereich liegen.
Ein beispeil:
Delphi-Quellcode:
type
ITemplateVariableStrategy = interface
['{FAE1E462-0E43-4B8E-A8D0-A594E0B25E67}']
function GetVariableValue(const VarName:string{; appearance:integer}):string;
function GetVariableOpenDelimiter:char;
function GetVariableCloseDelimiter:char;
end;
TAbstractTemplate = class(TObject)
private
FVariableStrategy:ITemplateVariableStrategy;
FOpenDelimiter: char;
FCloseDelimiter: char;
protected
...
public
constructor Create(TemplateVariableStrategy:ITemplateVariableStrategy); reintroduce;
function Process(const Text:String):string;
end;
In dem beispiel soll ein text-template-processor einen text auseinandernehmen und immer wenn eine variable auftaucht, sie durch ihren wert ersetzen. Weil der template prozessor wiederverwendbar sein soll, darf er nicht darüber entscheiden mit welchem zeichen einen variable (im templat-text) definiert wird. So, dafür befragt er einfach die strategie...
FOpenDelimiter := FVariableStrategy.GetVariableOpenDelimiter;
...und ist nun informiert. Nun findet er eine variable mit einem bestimmten namen und fragt wieder die strategie welchen text er denn nun einsetzen soll, weil er es selbst nicht entscheiden kann.
Es muss nur eine instanz geben die das entscheiden kann und die entsprechenden information liefert. Das kann die aufrufende instanz selbst sein, oder eine andere instanz die dafür geschaffen wurde und natürlich das interface implementiert:
Delphi-Quellcode:
TVariableContainer = class(TInterfacedObject, ITemplateVariableStrategy)
private
...
function GetVariable(const Name: string): TVariable;
public
constructor Create(OpenChar, CloseChar:char); overload;
constructor Create(OpenChar, CloseChar:char; Variables:array of TVariable); overload;
function GetVariableCloseDelimiter: Char;
function GetVariableOpenDelimiter: Char;
function GetVariableValue(const VarName: String): String;
procedure AddVar(aVar:TVariable);
procedure CreateVar(const aName, aValue:string);
procedure DeleteVar(const VarName:string);
...
end;
Als beispiel. Sie wird dann mit den information gefüttert und liefert die werte direkt an den template-processor.
So wird alles dynamisch gehalten und kann
sehr leicht ausgewechselt werden. Mit der definition einer schnitstelle schliesst man gewissermassen einen vertrag mit unbekannt, dass bestimmte aufgaben von ihm zu übernehmen sind, wenn er den vertrag implementiert (er kann den vertrag ja immernoch brechen, indem er exceptions schmeisst)
Das ist jetzt nur einen kleiner aspekt der schnittstellen-verwendung und sollte nur als anschauung dienen.
PS:
ich würd die referenzzählung nicht ausschalten!
mâxîmôv.
{KDT}