Interface für Datencontainer

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Interface für Datencontainer

Beitrag von m.fuchs »

Hallo,

ich bastele gerade an ein paar Komponenten, die eine Liste von Datensätzen (bestehend aus vier Eigenschaften) anzeigen sollen. Damit die Nutzung der Komponenten möglichst einfach in bestehende Systeme integriert werden kann, wollte ich diese Datensätze durch ein Interface definieren. Der Entwickler könnte dann einfach seine bestehenden Klassen anpassen, dass sie dieses Interface implementieren und diese an die Komponente übergeben. Dabei habe ich allerdings festgestellt, dass in ObjectPascal Interfaces keine abstrakten Properties enthalten können. :(

Nun stehe ich vor mehreren Möglichkeiten das Binden der Daten an die Komponenten zu bauen:
  • Ich definieren ein Interface, welches Rückgabemethoden für jede Eigenschaft enthält.

    Code: Alles auswählen

    IData = interface
      function GetStart: TDateTime;
      function GetEnd: TDateTime;
      function GetName: String;
      function GetTag: LongInt;
    end;
  • Alternativ enthält das Interface nur eine Methode, die einen Record mit den Daten als Paket zurückgibt.

    Code: Alles auswählen

    TDataPack = record
      Start, Ende: TDateTime;
      Name: String;
      Tag: LongInt;
    end;
     
    IData = interface
      function GetDataPack: TDataPack;
    end;
  • Oder ich verzichte ganz auf die Interfaces und lasse nur ein Array oder eine Liste des Records aus 2. an die Komponente binden.
Um meine Betriebsblindheit ein wenig zu kompensieren, bin ich auf der Suche nach Meinungen zu den oben genannten Vorgehensweisen (oder auch zu völlig neuen Ideen).

Eins noch im Voraus: Bitte nicht böse sein, wenn ich eure Vorschläge nicht berücksichtige. Ich werde aber definitiv alles lesen und durchdenken.

thx
Michael
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

linus
Beiträge: 22
Registriert: Di 19. Okt 2010, 17:23
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Kaiserstuhl

Re: Interface für Datencontainer

Beitrag von linus »

Hallo Michael - interessantes Thema.

Also, ich würde als Datenschnittstelle ein Listen-Objekt verwenden (am besten vielleicht sogar einen eigenen Schnittstellen-Typ als Nachfahr von TList einführen?) und ein Daten-Objekt (also keinen Record!) verwenden.

Denn: Wenn Du als Schnittstellen-Objekt ein Listen-Objekt verwendest kannst Du schon eine ganze Reihe von evtl. notwendigen Methoden vorsehen, z.B. für Sortierung, Einhängen und Aushängen von Objekten mit Plausi-Prüfungen u.v.a.m. (außerdem alles schön virtuell oder auch abstract deklariert falls nötig). Außerdem kann Dein Basis-Daten-Objekt die genannten 4 Datenfelder enthalten, wenn irgendwann neue Datenfelder dazukommen kann der Entwickler einen Nachfahr vom genannten Basis-Daten-Objekt deklarieren und die Listen-Schnittstelle bleibt davon unberührt.

Höre gerne Deine Meinung - Gruss Linus
Wer mehr denkt hat mehr vom Hirn...

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Interface für Datencontainer

Beitrag von Patito »

Hm. Also:

1. Sieht für mich normal aus.

2. Hat den Nachteil, dass es etwas unhandlicher ist wenn man die Schnittstelle ändern/erweitern will.
Man kriegt eventuell keine Warnung vom Compiler wenn man irgendwo vergessen hat ein Feld in den Record zu schieben, etc...
Bei den Interface-Funktionen ist es da schon wesentlich schwerer sich in den Fuß zu schießen.

3. Hat eben (wie ja schon erwähnt) den Nachteil, dass man es schwerer in bestehende Klassen einbauen kann.
Wenn, dann würde das dann eher Richtung Adapter-Klassen gehen, die die Daten nehmen und dann passend zum Komponenten-Interface übersetzen. Insgesamt wird das dann vom Code her etwas schwergewichtiger.

Konkret kommt es aber immer darauf an was man so braucht. Interfaces wie in 1. oder auch Daten-Klassen in Kombination
mit Daten-Factories und diversen Adaptern sind für mich üblich.

Insgesamt hat man bei Interfaces den Vorteil, dass man sich noch nicht auf eine Klassen-Hirarchie festnagelt.
So kann dann z.B. später zu einer besseren Klassen-Hirarchien wechseln ohne gleichzeitig alle 1000 alten Klassen ändern
zu müssen...

Nr 1. in Kombination mit abgeleiteten Interfaces kann auch Spaß machen:

Code: Alles auswählen

IDataEditor = interface(IData)
  procedure SetStart(const Value: TDateTime);
  procedure SetStop(const Value: TDateTime);
  procedure SetName(const Value: String);  
end;

Socke
Lazarusforum e. V.
Beiträge: 3177
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von Socke »

m.fuchs hat geschrieben:Dabei habe ich allerdings festgestellt, dass in ObjectPascal Interfaces keine abstrakten Properties enthalten können. :(
Interfaces sind ja schon per Defintion abstrakt (sind also an keine Implementation gebunden). Eigenschaften kann man auch verwenden (sind dann allerdings Pascal-spezifisch, während der Rest auch zu anderen Sprachen portiert werden kann); nur Eigenschaften ohne Getter-Methoden (und optionalen Setter-Methoden) sind nicht möglich:

Code: Alles auswählen

IData = interface
  function GetStart: TDateTime;
  function GetEnd: TDateTime;
  function GetName: String;
  function GetTag: LongInt;
  property Start: TDateTime read GetStart;
  property Ende: TDateTime read GetEnd;
  property Name: String read GetName;
  property Tag: Longint read GetTag;
end;
linus hat geschrieben:Nachfahr von TList einführen?
Solange du keine Methoden überschreibst, könnte ich dem sogar eingeschränkt zustimmen. Die vom FPC mitgelieferten Listen enthalten aus Geschwindigkeitsgründen keine (bzw. äußerst wenige) virtuellen Methoden und ohne die kanns bei abgeleiteten Klassen schnell recht langsam werden (besser eine TList-Instanz OOP-kapseln). Ich kann aber auch die Generics aus der Unit fgl empfehlen.
m.fuchs hat geschrieben:ich bastele gerade an ein paar Komponenten, die eine Liste von Datensätzen (bestehend aus vier Eigenschaften) anzeigen sollen.
Ich frage mich gerade, wozu du dieses Interface brauchst. Gib deiner Komponente eine Schnittstelle/Funktion, mit der die Daten übergeben werden können. Es ist oft aufwändiger wenn sich eine Komponente etwas holt, als wenn andere Komponenten ihr etwas geben...
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von Christian »

m.Fuchs, warum benutzt du keine DataSource um an die Daten zu kommen das hat den Charme das diene Komponente einfach so ziemlich jede Datensensitive Komponente ersetzen kann. Umgedreht geht das natürlich als Datenschnittstelle genauso indem man von TDataSet ableitet.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von m.fuchs »

Socke hat geschrieben:Interfaces sind ja schon per Defintion abstrakt (sind also an keine Implementation gebunden). Eigenschaften kann man auch verwenden (sind dann allerdings Pascal-spezifisch, während der Rest auch zu anderen Sprachen portiert werden kann); nur Eigenschaften ohne Getter-Methoden (und optionalen Setter-Methoden) sind nicht möglich
Genau das ist ja was mich stört. Ich würde am liebsten ein Interface definieren, welches einfach nur sagt: hier müssen vier Properties von folgendem Typ hin. Wie die dann implementiert werden, ob mit Getter-Methode oder per read auf ein privates Feld ist mir ja egal. Aber mit einem Interface was vier Get-Methoden hat könnte ich auch Leben.
Socke hat geschrieben:
m.fuchs hat geschrieben:ich bastele gerade an ein paar Komponenten, die eine Liste von Datensätzen (bestehend aus vier Eigenschaften) anzeigen sollen.
Ich frage mich gerade, wozu du dieses Interface brauchst. Gib deiner Komponente eine Schnittstelle/Funktion, mit der die Daten übergeben werden können. Es ist oft aufwändiger wenn sich eine Komponente etwas holt, als wenn andere Komponenten ihr etwas geben...
Ja, die Komponente hat ja diese Funktion und holt sich nichts. Das Interface ist bloß zur Datenkapselung. Es gibt dann in der Komponente eine Methode AddEntries und die bekommt ein Array/eine Liste von diesem Interface übergeben und zeigt die Daten dann an.
Ich könnte natürlich auch einfach eine fertige Datenklasse implementieren (die gibt es dort sogar, als Ableitung vom Interface) und nur die entgegen nehmen. Das bedeutet aber, dass bestehende Klassen die diese Daten enthalten erst konvertiert werden müssen. Mit einem Interface bräuchten die Klassen nur das zu implementieren und schön können sie direkt übergeben werden.
Christian hat geschrieben:m.Fuchs, warum benutzt du keine DataSource um an die Daten zu kommen das hat den Charme das diene Komponente einfach so ziemlich jede Datensensitive Komponente ersetzen kann. Umgedreht geht das natürlich als Datenschnittstelle genauso indem man von TDataSet ableitet.
Ehrlich gesagt, weil ich noch nie eins benutzt habe. Im allgemeinen benutze ich OR-Mapper oder Webservices um an die Daten zu kommen. Es gibt ein Model mit den Datenklassen und keinerlei DataSources/-sets zur Abfrage.

mfg
Michael
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3177
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von Socke »

m.fuchs hat geschrieben:Wie die dann implementiert werden, ob mit Getter-Methode oder per read auf ein privates Feld ist mir ja egal. Aber mit einem Interface was vier Get-Methoden hat könnte ich auch Leben.
Ein Interface kann nur Methodendeklarationen enthalten. Delphi erweiterte das ganze dann dahingehend, dass man die Methoden auch über Properties ansprechen kann (was jetzt nichts wirklich anderes ist).
m.fuchs hat geschrieben:Ja, die Komponente hat ja diese Funktion und holt sich nichts. Das Interface ist bloß zur Datenkapselung. Es gibt dann in der Komponente eine Methode AddEntries und die bekommt ein Array/eine Liste von diesem Interface übergeben und zeigt die Daten dann an.
In dem Falle sagst du ihr, wo sie die Daten bekommt. Im Endeffekt holt sie sich die Daten immer noch selbst.
m.fuchs hat geschrieben:Ich könnte natürlich auch einfach eine fertige Datenklasse implementieren (die gibt es dort sogar, als Ableitung vom Interface) und nur die entgegen nehmen. Das bedeutet aber, dass bestehende Klassen die diese Daten enthalten erst konvertiert werden müssen. Mit einem Interface bräuchten die Klassen nur das zu implementieren und schön können sie direkt übergeben werden.
Wenn ich das richtig verstehe, wäre der Unterschied doch wirklich marginal (wenn es wirklich nur darum geht, wie die Daten übergeben werden)

Code: Alles auswählen

// direkt mit Interface
myobj.AddEntries([obj1, obj2]);
// mit Datenobjekt/-struktur
myobj.AddEntries([obj1.AsData, obj2.AsData]);
Persönlich würde ich wahrscheinlich zu letzterem tendieren, da dann die einzelnen Datenmodelle besser voneinander getrennt werden können (siehe auch http://de.wikipedia.org/wiki/Model_View_Controller" onclick="window.open(this.href);return false;). Demnach definiert deine Anzeigeklasse genau ein Datenmodell, welches es anzeigen kann (Modell -> Klasse/Typ). Deine Daten werden dann zur Anzeige in das entsprechende Modell überführt (ansonsten könntest du es direkt von der Modell-Klasse ableiten).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von m.fuchs »

Socke hat geschrieben:
m.fuchs hat geschrieben:Ja, die Komponente hat ja diese Funktion und holt sich nichts. Das Interface ist bloß zur Datenkapselung. Es gibt dann in der Komponente eine Methode AddEntries und die bekommt ein Array/eine Liste von diesem Interface übergeben und zeigt die Daten dann an.
In dem Falle sagst du ihr, wo sie die Daten bekommt. Im Endeffekt holt sie sich die Daten immer noch selbst.
Sorry, das hab ich nicht verstanden. Wo holt sie sich die Daten selbst? Beim Zugriff auf die einzelnen Felder über die vier Get-Methoden? An irgendeiner Stelle müssen doch aber die Felder ausgelesen werden.

Vielleicht schreiben wir auch nur aneinander vorbei.

mfg
Michael
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3177
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von Socke »

m.fuchs hat geschrieben:Sorry, das hab ich nicht verstanden. Wo holt sie sich die Daten selbst? Beim Zugriff auf die einzelnen Felder über die vier Get-Methoden? An irgendeiner Stelle müssen doch aber die Felder ausgelesen werden.

Vielleicht schreiben wir auch nur aneinander vorbei.
Auch Möglich. Meine Argumentation wäre, dass die Klasse die Daten selbst abholt, sobald sie nicht mehr auf einen extra für sie geschaffenes Datenmodell zugreift. In diesem Fall also durch Zugriff auf die GetMethoden (die "irgendwetwas" tun).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Interface für Datencontainer

Beitrag von m.fuchs »

Socke hat geschrieben:Meine Argumentation wäre, dass die Klasse die Daten selbst abholt, sobald sie nicht mehr auf einen extra für sie geschaffenes Datenmodell zugreift. In diesem Fall also durch Zugriff auf die GetMethoden (die "irgendwetwas" tun).
Ok, das sehe ich aber anders. Ob ich nun vier Get-Abfragen in einem Objekt mache (über die vier Properties) oder vier Get-Abfragen in einem Objekt (über die vier definierten Methoden des Interface) bleibt doch gleich.

mfg
Micha
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten