Fragen zu Interfaces

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Benutzeravatar
photor
Beiträge: 259
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.12 FPC 3.2.2)
CPU-Target: 64Bit

Fragen zu Interfaces

Beitrag von photor »

Hallo Forum,

ich habe eine grundsätzliche Verständnisfrage - und vielleicht liege ich total daneben.

Ich will mich (eventuell) an ein für mich neues Thema wagen: Interfaces. Ich bin mir aber nicht sicher, ob es wirklich eine Lösung für mein "Problem" ist.

Das Problem: ich werkel (immer noch) an einem Programm zu einer Berechnung mit relativ vielen verschiedenen Eingabeparametern (Thema: Bruchmechanik). Diese Eingaben beziehen sich z.B. auf die Komponentengeometrie (mit diversen Abmessungen), -Material (diverse auch thematisch unterschiedliche Parameter), Lastannahmen (ebenfalls sehr unterschiedliche Bereiche, Kräfte, Momente direkt und in unterschiedlichen Kombinationen, oder auch nur die Spannungen dazu), Riss-Geometrie, ...

Für alle diese einzelnen Eingaben habe ich eigene Klassen definiert: TMaterial, TGeometry, TCrack, TLoads etc. Diesen Klassen/Bereichen ist im GUI jeweils ein Eingabe-Tab zugeordnet und in diesen werden je nach Problemstellung TEdits en- und disabled, je nachdem welche Eingabe-Parameter benötigt werden. Dazu muss ich irgendwo vorhalten, was wofür gesetzt werden muss - das mache ich im Moment in einem const array[], was aber schlecht zu warten ist.

Die Berechnungsroutine bekommt bisher eine Struktur/Klasse (TBerechnung) als Parameter übergeben, die die einzelnen Eingabeparameterklassen enthält, um nicht all diese Klassen (TLoad, TMaterial, TGeometry ...) in separaten Parametern zu übergeben.

Meine Idee: ich denke, es müsste doch möglich sein, für jede Problemstellung (z.B. Riss in Scheibe, Umlaufriss an Welle, elliptischer Innenriss ...) jeweils eine eigene Klasse zu definieren und dort alles zu regeln/definieren. Um jetzt nicht weiter mit diesen ganzen Parameter-Klassen zu hantieren, könnte man da nicht ein Interface definieren, dass all diese Parameter zusammen fasst, so dass die Berechnung sich die nötigen Parameter daraus zieht? Auf das könnte die jeweilige Problem-Klasse (mit den nur für dieses Problem benötigten Parametern) dann zugreifen und intern die Ergebnisse berechnen, die dann im GUI dargestellt werden (Diagramme, Listen).

Die Kernfrage ist wohl: Ist es möglich ein Interface zu definieren, dass die Properties und eventuell Berechnungsmethoden verschiedener benötigter Klassen so zusammenfasst?

Ich hoffe, ich habe halbwegs deutlich gemacht, was ich vorhabe bzw. versuchen will. Ich suche einfach Input zu dem Thema (positiv oder negativ), Anregungen, eventuell Anleitungen/HowTos zum Thema. Bitte entschuldigt, wenn das eigentlich super simpel oder im Gegenteil viel zu kompliziert gedacht ist - aber ich bin Anfänger in Sachen OOP (und ohne entsprechndes Studium), will aber lernen.

Vielen Dank für's durchlesen und eventuell antworten,
Photor

Benutzeravatar
Levario
Beiträge: 53
Registriert: Mo 1. Sep 2014, 14:32
OS, Lazarus, FPC: Windows 10 Pro Laptop (Lazarus 2.0.12 FPC 3.2)
CPU-Target: 64 Bit
Wohnort: Deutschland / NRW

Re: Fragen zu Interfaces

Beitrag von Levario »

Ich denke dein Problem ist leider zu themenspezifisch. Als Beispiel kannst du dir vielleicht einen Online Shop vorstellen in dem das Interface Artikel sind. Die einzelnen Artikel können CD's mit (Künstler, Autor, Lieder, Abspiellänge usw. sein) oder aber auch Bücher ( Autor, Buchlänge in Seiten oder Datengröße beim E-Book, Buchtyp, Verlag). Du kannst die einzelnen Produkte als eigene Klassen definieren.

Um auf dein Programm das abzuleiten, nimm dir Zeit alles was du benötigst als Mathematik aufzuschreiben und erstelle jeweils eine Funktion für die Berechnung und die benötigten Parameter. Für den Fall das sich da etwas ändert, kann man die Funktion ableiten und damit erweitern. Bei einem Bruch oder Riss könnten die Materialien als Bibliothek in einer Klasse oder Datenbank angelegt werden. Diese sollten für die Wartung und Erweiterbarkeit unabhänig sein. Ähnlich wie bei einem E-CAD Program die einzelnen Bausteine. Die GUI solltest du über Frames umsetzen, das hatten wir ja schon im letzten Post. Das Interface wäre hier die Berechnung und die immer wiederkehrenden Berechnungen die Methoden (Volumen eines Würfels, Die Berechnung eines Kreises) die du definiert. Du kannst das am besten selber definieren schreibe dafür alles auf ein Papier und lege die Zettel auf einen großen Tisch was kannst du vereinfachen kürzen in deinen Formeln. Die Methoden müssen kein Endergebnis bringen sondern können Teilergebnisse für deine Berechnung erstellen. Ein Artikel hat eine Artikelnummer genau wie eine CD oder ein Buch, eine Seitenzahl hat aber nur das Buch. Wichtig hierbei bei einem Interface sind die Methoden public definiert und damit angreifbar. Ich hoffe ich bin ein wenig verständlich.

Vielleicht hilft dir noch eine etwas andere Sichtweise. Stell dir dein Programm für die Umsetzung ohne GUI vor, oder als würdest du sie im nachinein implementieren und dann beginn mit einer Berechnung und allen möglichen Variablen. Alles was mehr als 1 Mal vorkommt kann als eigene Funktion (public und private) bzw. Methode (public) erstellt werden um doppelten Code zu vermeiden. Die Sichtweise ist auch interessant für eine eventuelle grafische Überarbeitung / Modernisierung des Programms die Mathe Funktionen und Material Bibliotheken können übernommen werden.

Ich habe meine ersten Programme ähnlich umgesetzt und schon bei der Auswahl ob Firmenkunde oder Privatkunde und die spezifischen unterschiedlichen Kundendaten waren schwer zu warten. Bei deinem Programm wird das ein Fass ohne Boden das sehr fehleranfällig und für andere Programmierer kaum wartbar wird. Ich meine damit die GUI, du solltest dir das nochmal mit den Frames durch den Kopf gehen lassen.
Der Weg ist das Ziel... Aber bitte nicht vergessen los zu laufen :).

kupferstecher
Beiträge: 302
Registriert: Do 17. Nov 2016, 11:52

Re: Fragen zu Interfaces

Beitrag von kupferstecher »

photor hat geschrieben:
Do 3. Jun 2021, 20:26
Meine Idee: ich denke, es müsste doch möglich sein, für jede Problemstellung (z.B. Riss in Scheibe, Umlaufriss an Welle, elliptischer Innenriss ...) jeweils eine eigene Klasse zu definieren und dort alles zu regeln/definieren.
[...]
Die Kernfrage ist wohl: Ist es möglich ein Interface zu definieren, dass die Properties und eventuell Berechnungsmethoden verschiedener benötigter Klassen so zusammenfasst?
Wenn ich dein Problem richtig verstanden habe, ist die Vererbung mit virtuellen Methoden das was du suchst.

Als Beispiel mit TGeometry:

Code: Alles auswählen

//Basisklasse
TGeometry = class
  Function GetMasse: Real; virtual;
 [...]
end;

//Spezialisierung
TVierkant = class(TGeometry)
  Function GetMasse: Real; override;
end;

//andere Spezialisierung
TRundstab = class(TGeometry)
  Function GetMasse: Real; override;
end;

//Klasse passend zu deiner Anwendung, hier im Beispiel eigentlich unnötig
TBerechnung = class
  Geometr: TGeometrie;
end;

var
 Berechn: TBerechnung;
 m: Real;
begin
  //Initialisierung  deines Lastfalles
  Berechn.Geometr:= TRundstab.Create; // Die Instanz wird in einer Variable der Basisklasse definiert!

  //Verwendung
  m:= Berechn.Geometr.GetMasse;  //Es wird die jeweilige GetMasse der tatsächlichen Klasse gerufen, nicht der Basisklasse
  Writeln('Masse:', m);
Kurz in Prosa: Die abgeleitete Klasse kannst du in einer Variablen mit Typ der Basisklasse ablegen und dann darauf zugreifen. "Virtual" sagt dem Compiler, dass es in abgeleiteten Klassen Methoden geben darf, die diese Überschreiben UND dass zur Laufzeit die zur Instanz passende Methode aufgerufen werden soll.

Würde man "virtual" und "override" weglassen (was auch geht), dann würde allerdings im obigen Beispiel nicht GetMasse von TRundstab aufgerufen, sondern von TGeometry, da die Variable Geometr vom Typ TGeometry ist.


Der Destruktor Destroy von der Klasse TObjekt (die Basisklasse aller Klassen) ist übrigens auch virtuell definiert und alle abgeleiteten Klassen sollten den Destruktor entsprechend mit override definieren. Damit kann die Instanz in der Variablen eines quasi beliebigen Typs gespeichert sein und trotzdem wird mit Variable.Free; die korrekte Methode der Instanz aufgerufen.

Benutzeravatar
photor
Beiträge: 259
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.12 FPC 3.2.2)
CPU-Target: 64Bit

Re: Fragen zu Interfaces

Beitrag von photor »

Moin,

"Danke" erstmal für Eure Anregungen bis hierher. Ich habe mir die Antworten ein bisschen durch den Kopf gehen lassen.

Basis-Klasse mit abgeleiteten Klassen habe ich schon bei der Implementation eines Loggings ausprobiert (das funktioniert auch erstmal - ob es gut umgesetzt ist, wird sich noch zeigen). Das wird auch weiterhin Mittel der Wahl sein - auch bezüglich der Definition der zusammenfassenden Problem-Klasse.

Mir geht es aber ja darum, die ganzen unterschiedlichen Informationsteile (Material, Bruchgeometrie, Komponentengeometrie, Lasten etc), die ich ja schon in Klassen organisiert habe, sinnvoll zusammen zu führen. Dabei dachte ich eben an ein Interface, dass dann die entsprechenden Bereiche aus der Klasse Material, der Klasse Geometrie, der Klasse Komponente etc zusammengefasst zur Verfügung stellt.

1. weiß ich nicht, ob das technisch geht und
2., ob es sinnvoll ist.

Bisher definiere ich mir halt ein Record/eine Klasse, die dann die entsprechende Klasse Material, Geometrie sowie Crack und Load enthält; diese übergebe ich dann als Parameter der Berechnungsroutine. Soweit klappt das auch - für eine dezidierte Problemstellung ("Umlaufriss auf Welle").

Bloß, sollen jetzt noch andere Problemstellungen dazu kommen. Und ich muss mir überlegen, wie ich das am beste organisiere. Ich würde tatsächlich eine Klasse pro Problem bevorzugen, die dann gleich die Berechnungsroutinen bereit stellen könnte (weil dann eventuell an leichtesten zu erweitern). Klar, das ist sehr problemspezifisch; aber mir fehlt halt das Grundlagenwissen dazu, um zu planen, um mich zu entscheiden.

BTW: die GUI halte ich strickt getrennt von den Rechenroutinen: alle(!) Parameter, die in der GUI gesetzt werden können, werden in einer dezidierten Struktur gespeichert, dort geupdatet, von dort bei Bedarf in einem INI-File gespeichert bzw. von da gelese und geupdatet. Alle(!) anderen Routinen greifen nur auf diese Struktur zu.

BTW2: Zu Interfaces habe ich in Nick Hodges "Coding in Delphi" nachgelesen, bin aber immer noch nicht s ganz sicher, ob das das meine ist.

Ciao,
Photor

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4609
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Fragen zu Interfaces

Beitrag von af0815 »

Beispiele für verwendung von Interfaces sind DirectShow (Windows) und GStreamer (Linux+WIn). Da werden laufend Interfaces verwendet. Grundlegend sind Interfaces Verträge über eine Schnittstelle ohne Implementierung. Der Vorteil von Interfaces ist, das da durch eine Entkopplung der Objekte eintritt und sie damit sich auch hervorragend eignen um getestet zu werden. OOP um das zu vererben, was Sinn macht, Interfaces um Objekte zu trennen und zu entkoppeln. Allerdings passt vieles nicht mit RAD zusammen :D

Bei DirectShow und gstreamer sieht man, wie die Schnittstellen sehr strict sind, aber über die Kombinierbarkeit der einzelnen Module wird es richtig genial.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Michl
Beiträge: 2425
Registriert: Di 19. Jun 2012, 12:54

Re: Fragen zu Interfaces

Beitrag von Michl »

Ist mMn eine Frage des persönlichen Geschmacks. Ich mag Interfaces nicht besonders. Wann immer ich so einen Ansatz probiert habe, bin ich letztlich wieder davon weg gekommen - aufgrund des debuggens und der Codetools oder meines beschränkten Horizonts (ich versuche den Code möglichst einfach, leicht verständlich und klar strukturiert zu halten um ihn dann später auch noch lesen bzw. warten zu können).

Wie Kupferstecher es schon empfohlen hat, würde ich sowas machen - nur exemplarisch:

Element (Klasse TElement)
mit
property Material (TMaterial)
property Geometry (TGeometry)
property Cracks (TCrackList)
property Loads
...

Als Basisklasse würde ich dann TCrack und TCrackList in einer separaten Unit definieren. Diese Unit hat quasi keine Abhängigkeiten und ist somit von überall abrufbar ohne zirkuläre Refferenz. Sie kann vollständig nur abstrakte Methoden enthalten oder aber nur wirklich zwingend notwendige von Logik unabhängige Properties. Z.B.:

Code: Alles auswählen

TCrack = class
private
  FReparable: Boolean;
public
  function Name: String; virtual; abstract;
  property Reparable: Boolean read FReparable write FReparable;
...
end;

TCrackList = specialize TFPGList<TCrack>;
Von TCrack würde ich die verschiedenen Fehler als Klasse ableiten, dort die Methoden von TCrack überschreiben und die speziellen Properties zufügen, jeweils in einer separaten Unit. Z.B.:

Code: Alles auswählen

TRissInScheibe = class(TCrack)
public
  function Name: String; override;
...
end;
Somit kann dann in das anfangs erwähnte Element.Cracks einfach per Element.Cracks.Add(InstanzOfTRissInScheibe) ein Fehler zugefügt werden.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
photor
Beiträge: 259
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.12 FPC 3.2.2)
CPU-Target: 64Bit

Re: Fragen zu Interfaces

Beitrag von photor »

Moin Michl,

Danke für Deine Anregungen. Zu den Bemerkungen bzgl. TCrack und TCrackList (und analog zu den anderen Größen): im Prinzip habe ich das bisher auch schon so organisiert. Ich werde da sicher noch mal drüber nachdenken müssen und geschickter aufteilen, als als das bisher der Fall ist (Vermeidung von zyklischen uses-Anweisungen etc).

Zu Deinen Anmerkungen wg. Interfaces: wenn es keinen großen Vorteil von Interfaces gegenüber der "herkömmlichen" Herangehensweise gibt - so interpretiere ich Deinen Text - dann werde ich das erstmal lassen. (meine Hauptmotivation war ja auch: lerne was neues! Und ich hatte halt gelesen, dass Interfaces Vorteile mit sich bringen).

Danke für den Input,
Photor

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4609
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Fragen zu Interfaces

Beitrag von af0815 »

photor hat geschrieben:
Mo 7. Jun 2021, 15:48
Und ich hatte halt gelesen, dass Interfaces Vorteile mit sich bringen).
Vorteil heisst nicht, weniger arbeit :-) Die Frage ist hier, wo setze ich die Grenze zwischen Vererbung und Interfacing.

Ein (englisches) Buch zu dem Thema ist 'Building Object Applications That Work' von Scott W. Ambler ISBN 0-521-64826-2 (978-0521648264). Das Buch ist zwar steinalt (1998 mit reprint in 2000) aber beleuchtet die verschiedenen Aspekte sehr gut. Auch zu den Anfängen der Pattern.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
photor
Beiträge: 259
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux (L 2.0.12 FPC 3.2.2)
CPU-Target: 64Bit

Re: Fragen zu Interfaces

Beitrag von photor »

af0815 hat geschrieben:
Mo 7. Jun 2021, 17:54
Vorteil heisst nicht, weniger arbeit :-) Die Frage ist hier, wo setze ich die Grenze zwischen Vererbung und Interfacing.
Das ist mir schon bewusst. Kann sein, dass etwas erst einmal mehr Arbeit macht, mir aber hinterher Vorteile (und dann auch weniger Arbeit) bringt (es geht nicht nur um die reine Schönheit; eher schon, was zu lernen).

Das Problem ist halt, dass ich das im Moment nicht überblicke. Daher meine Frage hier.
af0815 hat geschrieben:
Mo 7. Jun 2021, 17:54
Ein (englisches) Buch zu dem Thema ist 'Building Object Applications That Work' von Scott W. Ambler ISBN 0-521-64826-2 (978-0521648264). Das Buch ist zwar steinalt (1998 mit reprint in 2000) aber beleuchtet die verschiedenen Aspekte sehr gut. Auch zu den Anfängen der Pattern.
Ich werde mal suchen. Alles, was mich erhellt, ist willkommen.

Ich fange aber mal an, meine vorhandene Klassenstruktur anzupassen (ohne Interfaces).

Ciao,
Photor

Michl
Beiträge: 2425
Registriert: Di 19. Jun 2012, 12:54

Re: Fragen zu Interfaces

Beitrag von Michl »

photor hat geschrieben:
Mo 7. Jun 2021, 15:48
eine Hauptmotivation war ja auch: lerne was neues!
Das ist auf jeden Fall gut und zu unterstützen! Von daher probiere es aus!

Ich will dir zu Interfaces auch nicht zu- oder abraten, es muss dir passen! Und um dies herauszufinden würde ich dir empfehlen Testprojekte zu erstellen und zu testen, damit du ein Gefühl dafür bekommst. Erst danach würde ich die Implementierung in das echte Projekt vornehmen.

Ich spreche da leidlich aus Erfahrung. Ein großes Projekt von mir habe ich drei mal von Grund auf neu geschrieben, nicht weil es nicht lief, sondern weil es schlecht geschrieben war und mir später vor jeder Änderung graute :cry:

Jetzt habe ich meinen Frieden, versuche mich an KISS (Keep it simple, stupid) zu halten und es gibt immer vor dem Projekt ein/mehrere Tests bzw. Proof of Concepts (diese füllen, gut sortiert, einen Ordner, wo ich jederzeit schnell mal was testen kann).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4609
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Fragen zu Interfaces

Beitrag von af0815 »

Michl hat geschrieben:
Mo 7. Jun 2021, 21:18
Ich spreche da leidlich aus Erfahrung. Ein großes Projekt von mir habe ich drei mal von Grund auf neu geschrieben, nicht weil es nicht lief, sondern weil es schlecht geschrieben war und mir später vor jeder Änderung graute :cry:
Also der ganz normale Wahnsinn, den jeder mitmacht dessen Projekte größer werden :D

Das mit dem Testen und tests schreiben kann ich nur unterstützen. Wenn du eine Woche in ein Testprojekt steckst und dieses wegwirfst, weil du draufkommst das der Ansatz doch nicht so gut war, so gewinnst du später 2 Wochen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

BeniBela
Beiträge: 280
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Fragen zu Interfaces

Beitrag von BeniBela »

Ich hatte in einem Projekt records und habe es dann neu geschrieben. so dass es Klassen und Interfaces statt records verwendet

Nun überlege ich, es neuzuschreiben. so dass records statt Klassen und Interfaces verwendet

Benutzeravatar
six1
Beiträge: 403
Registriert: Do 1. Jul 2010, 19:01

Re: Fragen zu Interfaces

Beitrag von six1 »

af0815 hat geschrieben:
Mo 7. Jun 2021, 21:23
Michl hat geschrieben:
Mo 7. Jun 2021, 21:18
Ich spreche da leidlich aus Erfahrung. Ein großes Projekt von mir habe ich drei mal von Grund auf neu geschrieben, nicht weil es nicht lief, sondern weil es schlecht geschrieben war und mir später vor jeder Änderung graute :cry:
Also der ganz normale Wahnsinn, den jeder mitmacht dessen Projekte größer werden :D

Das mit dem Testen und tests schreiben kann ich nur unterstützen. Wenn du eine Woche in ein Testprojekt steckst und dieses wegwirfst, weil du draufkommst das der Ansatz doch nicht so gut war, so gewinnst du später 2 Wochen.
KISS habe ich auch immer im Auge...
Ich habe es immer gehasst, wenn sich jemand in "C" verausgabt hat und tonnenweise Sonderzeichen hingeschrieben hat und man nicht mehr geblickt hat, was der eigentlich macht oder was genau die Absicht war.
Schon deswegen, weil mein Kollege das auch lesen können muss --> KISS
Gruß, Michael

Antworten