Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#34

AW: Interfaces + Factorys

  Alt 1. Feb 2015, 14:05
Um Interfaces näher zu bringen würde ich eben ganz andere Beispiele nehmen, etwas, das man anfassen kann.

Wir haben z.B. eine Anwendung, die Dateien in einen Stream liest, die dann von der Anwendung weiterverarbeitet werden.

Dazu hat man sich eine schöne Klasse gebaut, die nun eine Datei in einen Stream einliest und diesen zurückgibt.
Delphi-Quellcode:
TFileStreamHandler = class
procedure GetStream( AFilename : string; AStream : TStream );
procedure WriteStream( AFilename : string; AStream : TStream );
end;
Vor allem ist das schick, wenn wir die Datei "$(Archiv1)\12345.doc" lesen wollen, setzt diese Klasse das gleich in den korrekten Pfad um Sehr geschmeidig.

Delphi-Quellcode:
procedure Foo( AHandler : TFileStreamHandler );
var
  LStream : TStream;
begin
  AHandler.GetStream( '$(Import)\Bild.jpg', LStream );
  AHandler.WriteStream( '$(Archiv)\123456.jpg', LStream );
end;
Alles ist gut, bis zu dem Tag, wo man feststellt, dass es besser wäre, diese Streams nicht wirklich in Dateien, sondern in einer Datenbank zu halten. Kein Problem, ändere ich einfach die Klasse ... hmmm, wie machen wir das bloss. Diese Klasse benutzen wir an jeder Stelle im Programm für jede Datei, auch für die, die weiter als Datei dort liegen.

Ganz einfach mit Interfaces:
Delphi-Quellcode:
IStreamHandler = interface
  procedure GetStream( AFilename : string; AStream : TStream );
  procedure WriteStream( AFilename : string; AStream : TStream );
end;

// die alte Klasse tut es ja noch
TFileStreamHandler = class( TInterfacedObject, IStreamHandler )
procedure GetStream( AFilename : string; AStream : TStream );
procedure WriteStream( AFilename : string; AStream : TStream );
end;
Die Anwendung ändere ich um, damit die mit dem Interface arbeitet
Delphi-Quellcode:
procedure Foo( AHandler : IStreamHandler );
var
  LStream : TStream;
begin
  AHandler.GetStream( '$(Import)\Bild.jpg', LStream );
  AHandler.WriteStream( '$(Archiv)\123456.jpg', LStream );
end;
Jetzt benötigen wir eine neue Klasse, die uns den Dateiinhalt aus der Datenbank holt/schreibt
Delphi-Quellcode:
TDatabaseStreamHandler = class( TInterfacedObject, IStreamHandler )
procedure GetStream( AFilename : string; AStream : TStream );
procedure WriteStream( AFilename : string; AStream : TStream );
end;
Und jetzt noch eine, die den Zugriff routet
Delphi-Quellcode:
TRoutedStreamHandler = class( TInterfacedObject, IStreamHandler )
procedure GetStream( AFilename : string; AStream : TStream );
procedure WriteStream( AFilename : string; AStream : TStream );
end;
Und erzeuge die Klasse z.B. mit
Delphi-Quellcode:
function GetStreamHandler : IStreamHandler;
var
  LFiles : IStreamHandler;
  LDatabase : IStreamHandler;
begin
  LFiles := TFileStreamHandler.Create;
  LDatabase := TDatabaseStreamHandler.Create( 'Server1', 'user', 'pass', 'archivdb' );

  Result := TRoutedStreamHandler.Create(
  {Default} LFiles,
  {} [
    {} 'Archiv', LDatabase,
    {} 'Archiv1', LDatabase ] );
end;
Welchen noch so ominösen Stream-Speicherort ich mir auch noch ausdenken werde (oder mir ausgedacht wird) ich erzeuge eine konkrete Klasse für diesen konkreten Ort und klatsche das in den Router mit rein. Die Anwendung arbeitet ohne weitere Änderungen wie gehabt weiter.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat