Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten? (https://www.delphipraxis.net/181764-designfrage-liste-selber-schreiben-oder-von-tlist-oder-tlist-t-ableiten.html)

mh166 8. Sep 2014 10:10

Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Hallo Leute,

ich bin im Moment gerade dabei für ein Projekt meine Klassen zu konzipieren und stehe dabei vor einer vermutlich eher trivialen Entscheidung. Dennoch würde ich gern eure Meinung dazu hören, ob ihr Argumente Für oder Wider habt — oder ob ihr der Meinung seid, dass es hier auf den persönlichen Geschmack ankommt.

Kurz zur Situation: ich habe verschiedene Klassen, für die ich jeweils Listen-Klassen erstellen möchte. Mal als Konzept in Pseudo-Code:
Delphi-Quellcode:
type
  TESPBase = class
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean; virtual;
    function DumpToJSON: String; virtual;
  end;

  TEmployee = class(TESPBase)
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean;
    function DumpToJSON: String;
    property ID: String;
    property FirstName: String;
    property LastName: String;
  end;

  TEmployeeList = class(TESPBase)
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean;
    function DumpToJSON: String;
    procedure Add(Elem: TEmployee);
    procedure Clear;
    procedure Delete(Index: Integer);
    procedure IndexOfID(SearchID: String);
    property Items[Index: Integer]: TEmployee;
    property ItemsByID[Index: String]: TEmployee;
  end;
Das soll jetzt mal als Beispiel dienen. Worum es mir jetzt geht: ich habe einige andere Klassen, die wie TEmployee im Beispiel, jeweils eine Listen-Klasse erhalten sollen. Im Großen und Ganzen unterscheiden diese sich jeweils nur durch diverse Properties und die Implementierung der Funktion LoadFromXML().

Ich würde an der Stelle jetzt eine Klasse TEspBaseList erstellen, von der ich dann sowohl TEmployeeList als auch alle anderen Listen ableiten kann.

Dafür sehe ich jetzt 3 Möglichkeiten:
  1. Klasse TEspBaseList selbst schreiben
    Vorteil: Ich könnte mich beim Funktionsumfang auf das beschränken, was für mich erforderlich ist. Ableitung von TEspBase ist möglich.
    Nachteil: Muss eben selber geschrieben werden. Ist jetzt kein zu großer Nachteil, aber kostet halt doch Zeit.
  2. Klasse TEspBaseList von TList ableiten
    Vorteil: Listenverwaltung komplett fertig und Einsatzbereit.
    Nachteil: Keine Ableitung von TEspBase möglich, da keine Mehrfachvererbung möglich ist.
  3. Klasse TEspBaseList von TList<TEmployee> ableiten
    Vorteil: ... ich hab ehrlich gesagt keine Ahnung was der Vorteil gegenüber #2 ist ...
    Nachtteil: Wie auch bei #2: kein Nachfahre von TEspBase.

Was würdet ihr an meiner Stelle tun? Gibt es noch Vor- oder Nachteile an die ich nicht gedacht habe? Oder ist das wirklich eine reine Geschmackssache?

Vielen Dank schon mal!

Gruß, mh166

Uwe Raabe 8. Sep 2014 10:17

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Hast du schon mal daran gedacht, die Funktionalität von TESPBase in zwei Interfaces zu verlagern? Damit brauchst du nicht mehr die gemeinsame Basisklasse. Das befreit ungemein...

mjustin 8. Sep 2014 10:20

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Kleine Randbemerkung:

die Basisklasse

Delphi-Quellcode:
  TESPBase = class
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean; virtual;
    function DumpToJSON: String; virtual;
  end;
ist fest an eine andere Klasse TJclSimpleXMLElem gebunden. Und alle abgeleiteten Klassen ebenfalls. Was wäre, wenn statt Jcl einmal eine andere XML Bibliothek verwendet werden soll?

Die Basisklasse sollte von der Konvertierung des Objekts nach/von JSON/XML unabhängig sein.

Lesetipp: http://de.wikipedia.org/wiki/Prinzip...LID-Prinzipien

Lemmy 8. Sep 2014 10:20

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
und dann noch die TList<> verwenden und nicht davon ableiten - dann hast Du noch weitere Freiheit dazu gewonnen...

Der schöne Günther 8. Sep 2014 10:23

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Ich mache selber immer noch zu viele Anfänger- und Deppenfehler um zu laut Ratschläge geben zu dürfen, aber:
  • Ich kann mir nichts vorstellen dass es rechtfertigen würde, nicht von einer bereits vorhandenen und vielfach eingesetzten Standardklasse abzuleiten. Warum sollte man das Rad nochmal neu erfinden?
  • Warum hat eine Liste plötzlich was mit JSON und XML zu tun? Was wirst du später alles noch drantackern? Deine Oracle-Datenbank? Eine Liste ist eine Liste. Nicht ein XML-Leser.
  • Lies mal ein Tutorial über Generics. Eine normale TList nimmt nur Pointer (meine ich). Da kannst du alles reinstecken. Nimm doch eine generische Liste- Die ist soweit "fertig" dass sie nur mit deinen Angestellten-Objekten arbeitet.
  • Grade bei weiteren Spezialfälle solltest du nicht von einer Liste ableiten, sondern an eine Liste (oder irgendeinen anderen Container) delegieren. Ob das Prinzip einen schnieken Namen (oder Abkürzung) hat weiß ich nicht.

mjustin 8. Sep 2014 10:26

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1271561)
Ich mache selber immer noch zu viele Anfänger- und Deppenfehler um zu laut Ratschläge geben zu dürfen, aber:
  • Ich kann mir nichts vorstellen dass es rechtfertigen würde, nicht von einer bereits vorhandenen und vielfach eingesetzten Standardklasse abzuleiten. Warum sollte man das Rad nochmal neu erfinden?


Ja, TList<> verwenden ist sicher richtig, wie Lemmy sagte allerdings nicht davon ableiten sondern sie private Variable intern als Datenspeicher nutzen, und nach aussen nur fachlich notwendige Methoden veröffentlichen (Hinzufügen/Entfernen/Suchen).

Genau das:

Zitat:

Zitat von Der schöne Günther (Beitrag 1271561)
  • Grade bei weiteren Spezialfälle solltest du nicht von einer Liste ableiten, sondern an eine Liste (oder irgendeinen anderen Container) delegieren. Ob das Prinzip einen schnieken Namen (oder Abkürzung) hat weiß ich nicht.

Information hiding ;), aber auch Open/Closed Prinzip

Stevie 8. Sep 2014 10:34

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mjustin (Beitrag 1271562)
Ja, TList<> verwenden ist sicher richtig, wie Lemmy sagte allerdings nicht davon ableiten sondern sie private Variable intern als Datenspeicher nutzen, und nach aussen nur fachlich notwendige Methoden veröffentlichen (Hinzufügen/Entfernen/Suchen).

Ja dann aber bitte nicht immer wieder für jede Datenklasse, die man in einer Liste braucht sondern eine generische mit nem Constraint auf TESPBase:

Delphi-Quellcode:
type
  TESPBase = class
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean; virtual;
    function DumpToJSON: String; virtual;
  end;

  TEmployee = class(TESPBase)
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean;
    function DumpToJSON: String;
    property ID: String;
    property FirstName: String;
    property LastName: String;
  end;

  TESPBaseList<T: TESPBase> = class(TESPBase)
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean;
    function DumpToJSON: String;
    procedure Add(Elem: T);
    procedure Clear;
    procedure Delete(Index: Integer);
    procedure IndexOfID(SearchID: String);
    property Items[Index: Integer]: T;
    property ItemsByID[Index: String]: T;
  end;

  TEmployeeList = TESPBaseList<TEmployee>;

mh166 8. Sep 2014 10:41

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1271557)
Hast du schon mal daran gedacht, die Funktionalität von TESPBase in zwei Interfaces zu verlagern? Damit brauchst du nicht mehr die gemeinsame Basisklasse. Das befreit ungemein...

Darüber hatte ich auch nachgedacht. Allerdings sind Interfaces, soweit ich weiß, nur Vorgaben, welche Funktionen implementiert werden müssen. In meinem Fall wäre das ja weniger das Problem: ich kann ja zweimal das gleiche implementieren, wenn ich mag. Nur will ich genau das vermeiden: Ich hätte zweimal 1:1 den gleichen Code, nur für 2 verschiedene Klassen. So zumindest hab ich das mit den Interfaces verstanden.

Zitat:

Zitat von mjustin (Beitrag 1271558)
Kleine Randbemerkung:
die Basisklasse [...] ist fest an eine andere Klasse TJclSimpleXMLElem gebunden. Und alle abgeleiteten Klassen ebenfalls. Was wäre, wenn statt Jcl einmal eine andere XML Bibliothek verwendet werden soll?

Da geb ich dir grundsätzlich recht. In anderen Projekten, wo solch ein Austausch wahrscheinlich ist oder ich nicht allein dran arbeite, gebe ich auf sowas in der Tat auch Acht: ich schreibe dann entweder Abstraktionen oder Provider, die dann jeweils im Detail implementiert werden. Hier allerdings handelt es sich um ein vergleichsweise kleines Projekt für den privaten Gebrauch. Da ist ein Austausch der XML-Klasse eher unwahrscheinlich. :)

Zitat:

Zitat von Der schöne Günther (Beitrag 1271561)
Warum hat eine Liste plötzlich was mit JSON und XML zu tun? Was wirst du später alles noch drantackern? Deine Oracle-Datenbank? Eine Liste ist eine Liste. Nicht ein XML-Leser.

Die Liste wird nur auf zwei Wege befüllt: a) XML-Response von einem Webserver auslesen. Und b) Elemente aus a) in eine nächste Liste stecken. Dementsprechend finde ich das durchaus passend, die Methode in die Klasse einzubinden. Was den JSON anbelangt: das ist mehr oder minder eine Debug-Funktion, die mir den Inhalt der Listen und/oder Klassen liefert.
[/quote]

Zitat:

Zitat von Der schöne Günther (Beitrag 1271561)
Lies mal ein Tutorial über Generics. Eine normale TList nimmt nur Pointer (meine ich). Da kannst du alles reinstecken. Nimm doch eine generische Liste- Die ist soweit "fertig" dass sie nur mit deinen Angestellten-Objekten arbeitet.

Werde ich tun. :)

Zitat:

Zitat von Stevie (Beitrag 1271564)
Ja dann aber bitte nicht immer wieder für jede Datenklasse, die man in einer Liste braucht sondern eine generische mit nem Constraint auf TESPBase:

Delphi-Quellcode:
  TESPBaseList<T: TESPBase> = class(TESPBase)
    constructor Create;
    destructor Destroy;
    function LoadFromXML(xml: TJclSimpleXMLElem): Boolean;
    function DumpToJSON: String;
    procedure Add(Elem: T);
    procedure Clear;
    procedure Delete(Index: Integer);
    procedure IndexOfID(SearchID: String);
    property Items[Index: Integer]: T;
    property ItemsByID[Index: String]: T;
  end;

  TEmployeeList = TESPBaseList<TEmployee>;

Das sieht natürlich sehr hübsch aus. :)

Uwe Raabe 8. Sep 2014 10:49

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mh166 (Beitrag 1271565)
Zitat:

Zitat von Uwe Raabe (Beitrag 1271557)
Hast du schon mal daran gedacht, die Funktionalität von TESPBase in zwei Interfaces zu verlagern? Damit brauchst du nicht mehr die gemeinsame Basisklasse. Das befreit ungemein...

Darüber hatte ich auch nachgedacht. Allerdings sind Interfaces, soweit ich weiß, nur Vorgaben, welche Funktionen implementiert werden müssen. In meinem Fall wäre das ja weniger das Problem: ich kann ja zweimal das gleiche implementieren, wenn ich mag. Nur will ich genau das vermeiden: Ich hätte zweimal 1:1 den gleichen Code, nur für 2 verschiedene Klassen. So zumindest hab ich das mit den Interfaces verstanden.

Solche Doppelimplementationen von Interfaces kann man dann wiederum mit einer Delegation auf eine andere implementierende Klasse auflösen (siehe reserviertes Wort implements).

BTW, könnte es sein, daß du in deinen abgeleiteten Klassen das override unterschlagen hast?

Der schöne Günther 8. Sep 2014 10:52

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mh166 (Beitrag 1271565)
Die Liste wird nur auf zwei Wege befüllt: a) XML-Response von einem Webserver auslesen. Und b) Elemente aus a) in eine nächste Liste stecken. Dementsprechend finde ich das durchaus passend, die Methode in die Klasse einzubinden. Was den JSON anbelangt: das ist mehr oder minder eine Debug-Funktion, die mir den Inhalt der Listen und/oder Klassen liefert.

Ein- und Ausgabe von und nach irgendwohin tackere ich mir selbst auch oft an Klassen, die es eigentlich nicht haben sollten. Ich will dich davor bewahren, so zu enden wie ich:
Es ist, wie der Name schon sagt, eine Liste. Kein Webserver-Response-Ausleser. Irgendwann hast du einen Webserver, der dir die Daten anders formatiert. Dann musst du deine Liste von Arbeitnehmern anpassen, nur weil sich ein Webserver geändert hat?

Grade wenn man einmal damit angefangen hat verleitet es immer weiter, die Klasse mit Dingen aufzublähen die sie nicht haben sollte. Irgendwann kommt eine Methode
Delphi-Quellcode:
massenentlassung()
welche anhand von irgendwelchen Kriterien Arbeitnehmer auswählt und sie entfernt. Sie stecken zwar in der Liste, aber die Liste selbst hat auch nicht die Filterung zu treffen, wer entfernt wird. Das nur als Beispiel. Schuster, bleib bei deinen Listen (höhö).

DeddyH 8. Sep 2014 10:55

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Günther hat am Samstag aufgepasst ;)

Der schöne Günther 8. Sep 2014 11:00

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Oh ja. Jetzt brauche ich nur noch diese Clean Code-Armbändchen. Oder ich lasse mir CLEAN CODE so auf die Finger tätowieren.

mh166 8. Sep 2014 11:03

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1271566)
Solche Doppelimplementationen von Interfaces kann man dann wiederum mit einer Delegation auf eine andere implementierende Klasse auflösen (siehe reserviertes Wort implements).

Zugegeben: bei meiner Suche nach Lösungen bin ich ja, wie gesagt, auch schon bei den Interfaces gelandet. Aber irgendwie war für mich die OH-Seite dazu wenig verständlich. Hab dann einfach bei Delphi-Treff das Tutorial zu Interfaces angeschaut. Hättest du eventuell ein kleines Beispiel, wie ich mir das vorstellen kann? =)

Zitat:

Zitat von Uwe Raabe (Beitrag 1271566)
BTW, könnte es sein, daß du in deinen abgeleiteten Klassen das override unterschlagen hast?

Öhm ... kööönnte wohl sein. :pale: War wohl doch etwas zu pseudo, der Code. 8-)

Zitat:

Zitat von Der schöne Günther (Beitrag 1271567)
Ein- und Ausgabe von und nach irgendwohin tackere ich mir selbst auch oft an Klassen, die es eigentlich nicht haben sollten. Ich will dich davor bewahren, so zu enden wie ich:
Es ist, wie der Name schon sagt, eine Liste. Kein Webserver-Response-Ausleser. Irgendwann hast du einen Webserver, der dir die Daten anders formatiert. Dann musst du deine Liste von Arbeitnehmern anpassen, nur weil sich ein Webserver geändert hat?

Ich gebe zu ... das ist durchaus plausibel und nachvollziehbar. =)

Zitat:

Zitat von Der schöne Günther (Beitrag 1271567)
Grade wenn man einmal damit angefangen hat verleitet es immer weiter, die Klasse mit Dingen aufzublähen die sie nicht haben sollte. Irgendwann kommt eine Methode
Delphi-Quellcode:
massenentlassung()
welche anhand von irgendwelchen Kriterien Arbeitnehmer auswählt und sie entfernt. Sie stecken zwar in der Liste, aber die Liste selbst hat auch nicht die Filterung zu treffen, wer entfernt wird. Das nur als Beispiel. Schuster, bleib bei deinen Listen (höhö).

Sag das nicht zu laut – so eine Funktion würde unser Betrieb sicher gern mal implementiert sehen. :D

Zitat:

Zitat von DeddyH (Beitrag 1271568)
Günther hat am Samstag aufgepasst ;)

Gabs hier im Forum was aufzupassen? =) Da würde ichs mir gern mal durchlesen, vielleicht ist ja auch für mich was nützliches bei. :stupid:

Der schöne Günther 8. Sep 2014 11:27

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mh166 (Beitrag 1271571)
Gabs hier im Forum was aufzupassen? =) Da würde ichs mir gern mal durchlesen, vielleicht ist ja auch für mich was nützliches bei. :stupid:

Das war ein Verweis auf Bernd Uas Vortrag "Besseren Code mit Delphi" vorgestern auf den Delphi-Tagen in Bonn. Ansonsten geht das Buch Clean Code in die selbe Richtung :-)


PS: Die beiden mittleren Zitate waren von mir, werden aber Uwe zugeschrieben. Verrückte Welt. Wenigstens haftet er jetzt juristisch für alle daraus entstehenden Schäden.

mh166 8. Sep 2014 14:47

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1271574)
Das war ein Verweis auf Bernd Uas Vortrag "Besseren Code mit Delphi" vorgestern auf den Delphi-Tagen in Bonn.

Ist es geplant, davon eine Aufzeichnung online zu stellen? Oder gibt es diese vielleicht ja sogar schon? :stupid:

Zitat:

Zitat von Der schöne Günther (Beitrag 1271574)
PS: Die beiden mittleren Zitate waren von mir, werden aber Uwe zugeschrieben. Verrückte Welt. Wenigstens haftet er jetzt juristisch für alle daraus entstehenden Schäden.

Da hab ich mich wohl verzitiert. :oops: Ist jetzt gefixed und du damit ab sofort wieder haftbar. :lol:

Uwe Raabe 8. Sep 2014 15:09

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mh166 (Beitrag 1271640)
Zitat:

Zitat von Der schöne Günther (Beitrag 1271574)
Das war ein Verweis auf Bernd Uas Vortrag "Besseren Code mit Delphi" vorgestern auf den Delphi-Tagen in Bonn.

Ist es geplant, davon eine Aufzeichnung online zu stellen? Oder gibt es diese vielleicht ja sogar schon? :stupid:

Dieses Jahr gab es leider keine Aufzeichnungen :(

Dejan Vu 8. Sep 2014 17:44

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Das Buch 'Clean Code' ist wirklich zum empfehlen. Die deutsche Version ist sehr gut geschrieben und verständlich. Gehört ins Regal wie früher Donald Knuth.

Uwe Raabe 8. Sep 2014 17:46

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Dejan Vu (Beitrag 1271673)
Gehört ins Regal wie früher Donald Knuth.

Wieso früher?

mh166 8. Sep 2014 18:19

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1271642)
Dieses Jahr gab es leider keine Aufzeichnungen :(

Das ist natürlich sehr schade. :(

Dürfte ich dich eventuell aber noch einmal um ein Beispiel für diese Delegation der Implementation von Interfaces bitten? :) Ich find irgendwie nix, dass ich so wirklich verstehe. :oops:

Der schöne Günther 8. Sep 2014 18:31

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Kurzfassung:
Delphi-Quellcode:
   // Delegiert das Krachmachen an einen TKrachmacher
   TWurstfabrik = class(TInterfacedObject, IKrachmacher)
      private var
         myKrachmacher: IKrachmacher;
      protected
         property krachDelegate: IKrachmacher
            read myKrachmacher
            implements IKrachmacher;
      public
         constructor Create();
   end;
Langfassung:
Delphi-Quellcode:
program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils;

type
   IKrachmacher = interface
   ['{CB618B3C-8057-4349-8CA3-8047907671A8}']
      procedure macheKrach();
   end;

   TKrachmacher = class(TInterfacedObject, IKrachmacher)
      public procedure macheKrach();
    end;

   // Delegiert das Krachmachen an einen TKrachmacher
   TWurstfabrik = class(TInterfacedObject, IKrachmacher)
      private var
         myKrachmacher: IKrachmacher;
      protected
         property krachDelegate: IKrachmacher
            read myKrachmacher
            implements IKrachmacher;
      public
         constructor Create();
   end;


{ TKrachmacher }

procedure TKrachmacher.macheKrach;
begin
   case Random(3) of
      0: WriteLn('<Ratter, ratter, quietsch>');
      1: WriteLn('*entweichender Dampf*');
      2: WriteLn('*heulende Sirene*');
   end;
end;

{ TWurstfabrik }

constructor TWurstfabrik.Create();
begin
   inherited Create();
   myKrachmacher := TKrachmacher.Create();
end;

var
   myKrachmacher: IKrachmacher;

begin
  try
   myKrachmacher := TWurstFabrik.Create();
   myKrachmacher.macheKrach();
   myKrachmacher.macheKrach();
   myKrachmacher.macheKrach();

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  ReadLn;
end.
Syntaxmäßig ein bisschen lang.
Delphi-Quellcode:
implements
kann man nur auf (eigentlich überflüssige) Properties anwenden, nicht direkt auf Felder.

Uwe Raabe 8. Sep 2014 18:50

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von mh166 (Beitrag 1271683)
Dürfte ich dich eventuell aber noch einmal um ein Beispiel für diese Delegation der Implementation von Interfaces bitten? :) Ich find irgendwie nix, dass ich so wirklich verstehe. :oops:

Ist zwar auch etwas gekünstelt, aber probieren wir es mal hiermit (Günther's Beispiel ist zugegeben etwas lustiger):

Delphi-Quellcode:
type
  TDumpToJSON = class
  private
    FInstance: TObject;
  protected
    function DumpToJSON: string;
    property Instance: TObject read FInstance;
  public
    constructor Create(AInstance: TObject);
  end;

  IDumpToJSON = interface
    function DumpToJSON: string;
  end;

  TMyClass = class(TInterfacedPersistent, IDumpToJSON)
  private
    FDumpToJSON: TDumpToJSON;
    function GetDumpToJSON: TDumpToJSON;
  protected
    property DumpToJSON: TDumpToJSON read GetDumpToJSON implements IDumpToJSON;
  public
    destructor Destroy; override;
  end;

  TMyOtherClass = class(TInterfacedPersistent, IDumpToJSON)
  private
    FDumpToJSON: TDumpToJSON;
    function GetDumpToJSON: TDumpToJSON;
  protected
    property DumpToJSON: TDumpToJSON read GetDumpToJSON implements IDumpToJSON;
  public
    destructor Destroy; override;
  end;

constructor TDumpToJSON.Create(AInstance: TObject);
begin
  inherited Create;
  FInstance := AInstance;
end;

function TDumpToJSON.DumpToJSON: string;
begin
  result := TJson.ObjectToJsonString(Instance);
end;

destructor TMyClass.Destroy;
begin
  FDumpToJSON.Free;
  inherited Destroy;
end;

function TMyClass.GetDumpToJSON: TDumpToJSON;
begin
  if FDumpToJSON = nil then begin
    FDumpToJSON := TDumpToJSON.Create(Self);
  end;
  result := FDumpToJSON;
end;

destructor TMyOtherClass.Destroy;
begin
  FDumpToJSON.Free;
  inherited Destroy;
end;

function TMyOtherClass.GetDumpToJSON: TDumpToJSON;
begin
  if FDumpToJSON = nil then begin
    FDumpToJSON := TDumpToJSON.Create(Self);
  end;
  result := FDumpToJSON;
end;

Sowohl TMyClass als auch TMyOtherClass leiten die Implementierung des Interfaces an die Instanz einer anderen Klasse TDumpToJSON weiter, die interessanterweise über IDumpToJSON gar nichts weiß.

Stevie 8. Sep 2014 19:06

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1271688)
Sowohl TMyClass als auch TMyOtherClass leiten die Implementierung des Interfaces an die Instanz einer anderen Klasse TDumpToJSON weiter, die interessanterweise über IDumpToJSON gar nichts weiß.

Der Nachteil hierbei ist allerdings, dass du hier die Abhängigkeit TDumpToJSON an alle deine IDumpToJSON fähigen Klassen hardcodest.
Und außerdem muss das TDumpToJSON nun für alle Klassen wissen, wie sie zu dumpen sind (wohlmöglich über RTTI, klar das geht).
Aber dann würde ich fragen, warum muss die dann in dem Objekt drin sein und warum muss son Objekt das Interface implementieren?

Bei nem bisschen Stringgematsche für JSON mag das noch harmlos sein, aber dann gehts los und jemand möchte die Instanzen in ner Datenbank speichern und schon haste irgendnen SQL oder Datenbank Zeugs an allen deinen Objekten kleben.

Andere Ansätze sind oft, dass die Klasse, die persistierbar ist, nur die Informationen ausspuckt, die so ein Persistierer benötigt (z.B. RTTI oder was selbstgebautes). Oder dass es ein Interface zum Persistierer übergeben bekommt und dann selbst seine Infos da rein schreibt.

Dann hast du maximal entkoppelte Klassen, so ne Liste oder Objekte wissen gar nix von ihrem Glück, persistierbar zu sein (möglicherweise nur über ihre RTTI/Attribute) und du kannst sie dann an die jeweiligen Instanzen geben, die diesen Job übernehmen.

Misko geht in diesem Artikel ein bisschen auf das Problem von diesen 2 Arten von Objekten ein - solche die einfach nur Daten halten (die er newable nennt) und solchen die wirkliche Arbeit durchführen (Injectables). Und welche Probleme bei der Architektur beim vermischen dieser beiden Arten passieren können.

mh166 9. Sep 2014 08:48

AW: Designfrage: Liste selber schreiben? Oder von TList oder TList<T> ableiten?
 
Vielen Dank an Günther und Uwe: ich glaub ich habs jetzt verstanden. Wobei ich ehrlich gesagt den Umweg über eine extra Property dafür vergleichsweise hacky finde. :? Aber gut, wenn Delphi es so will ... Zumindest weiß ich jetzt, wies funktioniert.

Für den Moment hab ich aber erstmal diese Lösung von Stevie genutzt. Ist an der Stelle die praktikablere Methode für mich, da es nur um drei oder vier Zeilen Code geht, der zweimal dasteht. Ist demnach lesbarer und übersichtlicher wenn man nicht noch 20 Zeilen Interface und Implementierung drumherum baut. :)

Vielen Dank euch allen! Hab wieder ne ganze Menge hierbei gelernt. :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz