![]() |
AW: Interfaces - Multiple Inheritance
Wozu willst du mehrere Interfaces vererben?
IRead und IWrite und dann wird eines von Beiden oder Beides bei den entsprechenden Klassen angegeben. Sowas geht zwar auch
Delphi-Quellcode:
oder sowas
type
IRead = interface function ReadInt: Integer; end; IWrite = interface procedure WriteInt(Value: Integer); end; IReadWrite = interface function ReadInt: Integer; procedure WriteInt(Value: Integer); end;
Delphi-Quellcode:
Aber da muß man dann bei den Funktionen, welche auf diese Interfaces prüfen, die Interfaces doppelt abfragen, da es je "Funktion" zwei Interfaces gibt.
type
IRead = interface function ReadInt: Integer; end; IWrite = interface procedure WriteInt(Value: Integer); end; IReadWrite = interface(IRead) procedure WriteInt(Value: Integer); end; Read = IRead oder IReadWrite Write = IWrite oder IReadWrite |
AW: Interfaces - Multiple Inheritance
Zudem man bei der Klasse (wie schon mehrfach erwähnt) jedes Interface angeben muss.
Somit hilft einem dieses Multi-Erben auch nicht wirklich. BTW Wenn man die implementierende Klasse nicht von
Delphi-Quellcode:
ableiten möchte.
TInterfacedObject
Delphi-Quellcode:
dann kann man das auch nicht gegen das Basis-Interface
type
IMyInterface = interface end; TMyInterfacedObject = class( TObject, IMyInterface ) ... end;
Delphi-Quellcode:
casten.
IInterface
|
AW: Interfaces - Multiple Inheritance
Da muss ich offenbar noch etwas drauf rum denken...
Mit der Klassendefinition habe ich kein Problem. Wenn ich die Objekte in einer Factory erzeugen lasse und nur mit den Interfaces weiter arbeite, dann erscheint mir eine Mehrfachvererbung doch sinnvoll.
Delphi-Quellcode:
In RW sind beide Funktionalitäten deklariert.
var RW: IReadWrite;
X: Integer; ... RW := TFactory.GetNewRW; // erzeugt ein TReadWrite und gibt es als IReadWrite zurück ... // folgendes ist möglich RW.WriteInt(1); X := RW.ReadInt; // bzw. auch über Property RW.Int := 1; X := RW.Int; IReadWrite selbst könnte einfach so definiert sein:
Delphi-Quellcode:
IReadWrite = Interface(IRead, IWrite);
end; Ohne diese Mehrfachvererbung muss man die Funktionen (mindestens zum Teil) in den Interfacedefinitionen doppelt schreiben. Wenn man RW nicht als IReadWrite definiert sondern als "BasisInterface" muss man immer Supports verwenden und casten. PS: Gibt es denn irgendwo ein Delphi-Tutorial, wie man korrekt mit einer Factory und komplexen Schnittstellen arbeitet? So ganz konkret habe ich dazu noch nichts gefunden. Vielleicht bin ich ja noch etwas auf dem Holzweg... (Das ![]() |
AW: Interfaces - Multiple Inheritance
Warum denn nicht einfach kreativ so
Delphi-Quellcode:
IRead = interface
function Read : Integer; end; IWrite = interface procedure Write( Value : Integer ); end; IReadWrite = Interface; function Reader : IRead; function Writer : IWrite; end; TReadWrite = class( TInterfacedObject, IRead, IWrite, IReadWrite ) private FValue : Integer; public // IRead function Read : Integer; // IWrite procedure Write( Value : Integer ); // IReadWrite function Reader : IRead; function Writer : IWrite; end; function TReadWrite.Read : Integer; begin Result := FValue; end; procedure Write( Value : Integer ); begin FValue := Value; end; function Reader : IRead; begin Result := Self; end; function Writer : IWrite; begin Result := Self; end; |
AW: Interfaces - Multiple Inheritance
Nur als Einwurf, etwas OT aber auch nicht ganz. Interface-Vererbung, zumal mehrfache/tiefe Vererbung, halte ich so ganz aus dem Bauch heraus für mitunter fragwürdig. Oft endet es dann, dass man eine komplexe Hierarchie Interfaces definiert, welche dann fast 1:1 als Hierarchie von Klassen implementiert wird. Der Gedanke, ein Interface als eine Art "Service" zu sehen, den ein Objekt anbietet/unterstützt, fällt dabei vollkommen heraus. Die meisten Interfaces sollten wohl eher "schlank" sein.
Und jetzt lese ich mir mal durch, warum man in Delphi die implementierten Interfaces explizit angeben muss. Mich hat das schon mehr als einmal genervt... Schöne Feiertage btw! |
AW: Interfaces - Multiple Inheritance
Das ist ein guter Einwand.
Wenn man aber die Instanziierung der Klassen (Erzeugen der Objekte) auslagert und fortan nur noch mit Interfaces arbeiten will, dann braucht man wiederum mächtige Interfaces, die die gesamte Funktionalität veröffentlichen. Andernfalls müsste man immer prüfen, ob das vorliegende (Objekt-)Interface nun gerade zufällig IRead oder IWrite unterstützt, darauf casten und dann auf die Propertys zugreifen. Andererseits bringt das natürlich auch wieder Vorteile, da man so sehr flexibel mit den Objekt-Interfaces umgehen kann. Eigentlich bräuchte man dann IReadWrite gar nicht sondern würde einfach mit IInterface arbeiten:
Delphi-Quellcode:
var RW: IInterface;
X: Integer; ... RW := TFactory.GetNewRW; // erzeugt ein TReadWrite und gibt es als IInterface zurück ... if Supports(RW, IWrite) then (RW as IWrite).WriteInt(1); if Supports(RW, IRead) then X := (RW as IRead).ReadInt; // bzw. auch über Property if Supports(RW, IWrite) then RW.Int := 1; if Supports(RW, IRead) then X := (RW as IRead).Int; Dann braucht man sich gar nicht mehr kümmern, was genau da für ein Objekt vorliegt (eigentlich ja der Sinn von Interfaces). Wenn man sicher ist, was man übergibt kann man Supports ja notfalls weg lassen. Alternativ könnte man natürlich noch Variablen wie R: IRead und W: IWrite einführen. Auf jeden Fall könnte man auf mächtige Schnittstellen als Klassenkopien so verzichten. Aktuell scheint mir der Ansatz eigentlich sinnvoll zu sein (kann sich aber wieder ändern ;-)). Ginge das so? |
AW: Interfaces - Multiple Inheritance
Wenn man sich an das
![]() ![]() Genau genommen ist schon allein das Supports abfragen des einen Interfaces auf das andere ein Code Smell, denn dadurch greift man von hinten rum auf etwas zu, was einem gar nicht übergeben wurde. Wenn ich möchte, dass nur lesender Zugriff erfolgt, übergeb ich das IRead Interface. Wenn sich nun jemand mit Supports mal ebend aus diesem Interface Schreibzugriff besorgt, ist das ziemlich bedenklich. |
AW: Interfaces - Multiple Inheritance
Ok, die ersten 2 Sätze kann ich nachvollziehen.
Aber das Supports stinkt nicht so ganz. Wenn ich einer Funktion bestimmte Objekt-Interfaces (also quasi irgendwelche Objekte) übergebe und dann diverse Dinge damit tun will, dann muss ich doch wissen, was ich vor mir habe. Z.B. kann ich prüfen, ob ISerialization unterstützt wird und das Objekt dann serialisieren. Wenn IOrganic unterstützt wird kann ich DoDestroying(1) aufrufen usw. Dass Supports schlecht sein soll, erschließt sich mir irgendwie nicht. NACHTRAG: Wenn ich absichtlich ein allgemeines Interface übergebe und damit ausdrücklich unterschiedliche Aktionen ermöglichen will, müsste mein Ansatz doch korrekt sein? Ich sehe ein, dass der Ansatz fragwürdig wäre, wenn tatsächlich nur IRead übergeben wird und das Objekt aber dennoch auseinander genommen würde (ähnlich wie mit der RTTI). |
AW: Interfaces - Multiple Inheritance
Zitat:
Ich kann aber auch Interfaces als Services übergeben (im Gegensatz zu Datenobjekten sind das Klassen bzw Interfaces, die irgendwelche Arbeit erledigen) und da sollte man aufpassen, irgendwelche Annahmen darüber zu machen, welche Interfaces möglicherweise noch implementiert sind (Stichwort ![]() Zu dem oben angesprochenen Punkt. Wenn Datenobjekte allerlei Interfaces implementieren, die dann irgendwas mit dem Objekt machen, handelt man sich sehr schnell Probleme mit dem SRP ein (das Objekt hält also nicht nur Daten, sondern Serialisiert sich, schreibt sich in die Datenbank, kann sich ausdrucken und vieles mehr). Zudem kommt es dann auch sehr schnell zu einer vermischung von verschiedenen Layern, die nix miteinander zu tun haben. Ich will damit nicht sagen, dass man das keineswegs machen sollte, aber man sollte aufpassen, welche Funktionalität man damit zur Verfügung stellt und inwieweit man seine Datenobjekte dann von anderen Schnittstellen abhängig macht. |
AW: Interfaces - Multiple Inheritance
Zitat:
Dann braucht man nur noch jeweils Eines der Drei anzugeben. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:16 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 by Thomas Breitkreuz