![]() |
vererbende Klasse oder Interface? oder beides?
Hallo. Ich bin gerade am kämpfen/lernen mit Vererbung und Interfaces und bräuchte da mal eine kompetente Meinung.
Meine Problemstellung: Ich habe verschiedene Messgeräte die ich über GPIB anspreche. Das Schreiben/Lesen ist bei den Messgeräten unterschiedlich. Deshalb wollte ich ein Interface ISchreibenLesen verwenden, dessen Methoden dann jede Klasse implementieren muss. Theoretisch könnte ich ja aber auch abstrakte Methoden in der Oberklasse deklarieren und diese dann jeweils in der Unterklasse überschreiben. Kann man da sagen was besser ist? Die Oberklasse hatte ich mir gedacht, da ja alle Messgeräte gewisse gemeinsame Felder besitzen (Adresse usw.) TMessgeräte = class ((TInterfacedObject)) TMessgerätA = class (TMessgeräte, ISchreibenLesen) TMessgerätB = class (TMessgeräte, ISchreibenLesen) Und noch eine Frage. Die Messgeräte sollen eine Property Range bekommen (mit Getter und Setter). In der Oberklasse deklariert, wird die Property an die Unterklassen vererbt, die Getter/Setter müssten dann abstract sein. Oder anders, die Property im Interface deklarieren (hier auch Getter/Setter). Dann muss ich in der Unterklasse aber wieder eine Property deklarieren, das wird irgendwie doch nicht mehr so übersichtlich. Wie würdet ihr sowas machen? Wie gesagt, bin da noch stark am Anfang mit Interfaces und Vererbung und für jede Anregung dankbar. Grüße |
AW: vererbende Klasse oder Interface? oder beides?
Ob besser oder schlechter kann man hier nicht sagen. Das kommt wesentlich auf den Rest der Anwendung an. Interfaces bieten Referenzzählung, blähen den Code aber auch etwas auf. Wenn du alles auf einen gemeinsamen Vorfahren zurückführen kannst, ist eine abstrakte Klasse auch keine schlechte Wahl.
Die Getter und Setter kannst du problemlos als abstract deklarieren. Die abgeleitete Klasse braucht dann auch nicht das Property nochmal zu deklarieren - es genügt, wenn die Getter und Setter überschrieben werden. |
AW: vererbende Klasse oder Interface? oder beides?
Hallo,
Interfaces bieten zwei grundlegende Vorteile: 1. Durch die Referenzzählung müssen Sie nicht explizit freigegeben werden. 2. Ein Interface kann von verschiedenen Objekten implementiert werden, die gerade nicht über einen gemeinsamen Vorfahren verfügen. Da Du in Deinem Beispiel den gemeinsamen Vorfahren TMessgerät hast, denke ich, dass Du keine Interfaces benötigst. In Deinem Beispiel kannst Du übrigens bereits das TMessgerät mit dem Interface ISchreibenLesen verbinden, da die Erben es ohnehin bereitstellen sollen. -- Viele Grüße, Roman Kassebaum Embarcadero Technology Partner Embarcadero MVP Blog: ![]() |
AW: vererbende Klasse oder Interface? oder beides?
Ok, Danke. Das war schon mal sehr interessant.
Wenn ich das Interface ISchreibenLesen mit der Oberklasse TMessgeräte verbinde, dann müsste ich doch eigentlich die Methoden auch in TMessgeräte implementieren. Das möchte ich ja aber erst in den abgeleiteten Klassen. Also müsste ich ja folglich die vom Interface bereitgestellten Methoden als abstract deklarieren. In meinem Fall ist das vielleicht zuviel des Guten und ich deklariere die Methoden gleich in TMessgeräte ohne das Interface. Ansonsten wäre ja 3-mal eine Methode deklariert (im Interface, Oberklasse, Unterklasse) + die Implementierung. Das kann schon auch unübersichtlich werden. Werd mich mal ran machen das umzusetzen! |
AW: vererbende Klasse oder Interface? oder beides?
Genau das gefällt mir auch nicht wirklich. Die Schuld liegt da irgendwie eher an der Delphi-Sprache selber, "echte" abstrakte Klassen kennt es nicht.
Delphi-Quellcode:
INeustartbar = interface
['{C952DFE2-65A3-48A4-8681-81F97946DB5A}'] procedure restart(); end; ISchreibenLesen = interface ['{DBAF7078-C915-471F-8C37-F679253220BE}'] procedure writeStuff(); procedure readStuff(); end; ( AMessgerät = class abstract(TInterfacedObject, ISchreibenLesen) public // Warum ist das hier überhaupt notwendig? procedure readStuff; virtual; abstract; procedure writeStuff; virtual; abstract; end; TMessgerät1 = class(AMessgerät) procedure spezialKram(); end; TMessgerät2 = class(AMessgerät, INeustartbar) public procedure spezialKram(); procedure restart(); end; |
AW: vererbende Klasse oder Interface? oder beides?
Ich hatte ja gestern schon gesagt, dass man Interfaces sehr gut nutzen kann, um Objekte, die keinen gemeinsamen Vorfahren habe, anzusprechen.
Für die zweite Aufgabe, die Referenzzählung, kann man übrigens auch einen ObjGuard ( ![]() Was mir an der vorgestellten Lösung überhaupt nicht gefällt, ist, dass man von TInterfacedObject ableiten muss. Dadurch "weiß" TMessgerät bereits, dass die abgeleiteten Klassen Interfaces nutzen werden. Ich würde also die Interfaces weglassen. -- Roman Kassebaum Embarcadero Technology Partner Embarcadero MVP Blog: ![]() |
AW: vererbende Klasse oder Interface? oder beides?
Delphi-Quellcode:
Das geht genauso. Das Interface muss man ja nicht in der Oberklasse angeben.
INeustartbar = interface
['{C952DFE2-65A3-48A4-8681-81F97946DB5A}'] procedure restart(); end; ISchreibenLesen = interface ['{DBAF7078-C915-471F-8C37-F679253220BE}'] procedure writeStuff(); procedure readStuff(); end; TMessgerät = class abstract(TInterfacedObject) end; TMessgerät1 = class(TMessgerät, ISchreibenLesen) procedure readStuff; procedure writeStuff; procedure spezialKram(); end; TMessgerät2 = class(TMessgerät, ISchreibenLesen, INeustartbar) public procedure readStuff; procedure writeStuff; procedure spezialKram(); procedure restart(); end;
Delphi-Quellcode:
(Wobei das Objekt nach der Methode durch das Interface freigegeben wird.)
var
a: TMessgerät; b: ISchreibenLesen; begin a := TMessgerät2.Create; b := a as ISchreibenLesen; b.readStuff; end; // EDIT: Zitat:
|
AW: vererbende Klasse oder Interface? oder beides?
Es ist ganz wichtig, dass Du die Objektinstanz nicht in einer Variablen merkst. Sobald die Referenzzählung das Objekt freigibt, wäre die Instanz nicht mehr gültig.
Delphi-Quellcode:
--
var
b: ISchreibenLesen; begin b := TMessgerät2.Create; b.readStuff; end; Roman Kassebaum Embarcadero Technology Partner Embarcadero MVP Blog: ![]() |
AW: vererbende Klasse oder Interface? oder beides?
Außer zur Initialisierung in einer lokalen Variable, da finde ich das in Ordnung. Aber sobald das Objekt das erste Mal in einer Interfacereferenz gelandet ist, darf man die Objektvariable natürlich nicht mehr nutzen.
Deshalb ist es auch besser entweder Interfaces oder Objekte zu nutzen und das durch die gesamte Vererbung durch. Oder man deaktiviert die Referenzzählung. |
AW: vererbende Klasse oder Interface? oder beides?
Ich würde Datentransport und Datenaufbereitung strikt voreinander trennen.
Das bedeutet dass es eine Klasse für GPIB gibt die rein nur für den Datentransport zuständig ist und eine weitere (Basis-)Klasse TMessGeraet die für die Aufbereitung der Daten verantwortlich ist. Dabei benützt die Klasse TMessGeraet ihren Kollegen TGPIB. ( ![]() Es liegt also weder eine Vererbung vor noch benötigt man ein Interface. Man könnte sogar eine weitere Klasse für das Datenprotokoll einsetzen falls ein einheitliches Protokoll wie CS-80 (Command Set 80) benützt wird. Man kann diesen Ansatz mit folgender Kette vergleichen:
Code:
TDatabase sorgt für den Datentransport
TDatabase <- TQuery <- TDBEdit
TQuery entspricht praktisch dem Protokoll auf Datenbankebene und TDBEdit repräsentiert die Daten auf Anwendungsebene. Jede Klasse dient nur einem bestimmten Zweck wobei die Klassen miteinander kollaborieren und in einer "benützt"-Beziehung stehen. Wichtig ist noch die Pfeilrichtung der Abhängigkeiten zu beachten. Die Klasse TGPIB darf die Klasse TMessGeraet nicht kennen; umgekehrt kennt und benützt aber TMessgeraet die Klasse TGPIB. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:20 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz