![]() |
Delphi-Version: 7
gemischter Interface-/Objektzugriff
Servus,
beim Einsatz von Interfaces muss man ja tunlichst darauf achten, Interfaces und Objektzugriff nicht zu mischen, da es sonst zur automatischen Freigabe kommen kann, da die Objektvariable nicht zum RefCount zählt. Nehmen wir folgendes Beispiel
Delphi-Quellcode:
IFooItem = Interface
['{9995E78E-45DF-4C25-B657-7396738FEA70}'] procedure Bar; end; TFooItem = class(TinterfacedObject, IFooItem) public procedure Bar; procedure Foo(const AValue); end; Der Konsument meines Interfaces muss lediglich auf die Methode Bar zugreifen. Allerdings benötige ich beim Erzeugen / Initialisieren / Aktualisieren in meinem Owner der Objektinstanz auch die Methode Foo.
Delphi-Quellcode:
Greife ich mit dem Code oben einmal auf Item zu wird aus dem FItem das Interface geholt, übergeben und wenn die aufrufende Methode beendet ist, wird das Interface genilt, der Refcounter kommt bei 0 an und FItem wird frei gegeben.
TFooOwner = class
private Fitem: TFooItem function GetItem: IFooItem public property Item: IFooItem getItem; procedure ChangeItem(const AValue); end;# .... procedure TFooOwner.ChangeItem(const AValue) begin FItem.Foo(AValue); end; Die einzige Lösung für das Problem die ich kenne wäre, die Referenzzählung zu "deaktivieren". Die Freigabe der Instanz ist ja kein Problem, da ein Eigentümer da ist, der sich darum kümmert. Allerdings wird im Netz (und auch hier) davon abgeraten die Referenzzählung zu umgehen - nur warum? Oder Alternativ: Welche andere Möglichkeit gibt es für eine solche Implementierung? |
AW: gemischter Interface-/Objektzugriff
Grundsätzlich gilt: Solange du weißt, was du tust, ist alles erlaubt.
Für deinen Fall würde ich statt von
Delphi-Quellcode:
von
TInterfacedObject
Delphi-Quellcode:
ableiten, das genau dafür gemacht ist.
TInterfacedPersistent
|
AW: gemischter Interface-/Objektzugriff
Erstmal mußt du entscheiden was führend ist und der Großteil der Referenzen sollte dann in Modus sein.
1: Interface mit Referenzzählung und wenn nötig, dann wird daraus "kurzzeitig" eine Objektreferenz geholt (z.B. TInterfacedObject) 2: Objekt ohne Referenzzählung ist führend und man kann daraus kurzzeitig Interfacereferenzen holen (z.B. TInterfacedPersistent) Ein Beispiel für 2 ist die VCL, da kannst du jedes TComponent nach einem Interface fragen und so gleiche Funktionalität in unterschiedliche Klassen (auch nachträglich) einbauen. PS: Etwas neuere Delphis können auch
Delphi-Quellcode:
, da dort ein virtuelles Interface in TObject steckt, was "intern" per Supports statt einer Interfacereferenz die Objektreferenz raus holt, ohne das man selber ein GetMyObject (Result := Self) bauen muß.
MyIntf as TMyObject
PPS: Unter ARC hat Delphi Interfaces und Objekte vermanscht. Beides ist "immer" referenzgezählt (außer bei
Delphi-Quellcode:
) und nutzt eine gemeinsame Zählung.
var [Weak] Variable: xxx;
|
AW: gemischter Interface-/Objektzugriff
Zitat:
ich weiß, dass ich nichts weiß.... :-) Danke für Eure Tipps, über TInterfacedPersistent bin ich auch schon gestolpert, war mir aber etwas unsicher bzgl. des FOwnerInterface. Schaut aber ganz gut aus im ersten Test... Zitat:
|
AW: gemischter Interface-/Objektzugriff
Eigentlich ist es ja böse, wenn man aus einem "abstrakten" Inteface ein Objekt macht, da ja die Implementation hinter dem Interface eigentlich "geheim" ist.
Aber aus Sicht des Delphi und wenn man hinter dem Interface ein Objekt hat, ist es so vollständiger. * Objekt zu Interace geht ja schon ewig und ganz einfach (auch ohne ![]() * und nun auch andersrum Geht seit Galileo-IDE Version 7, also ab Delphi 2010. Blöd für dich ... Delphi 7 ist Delphi-IDE Version 7, aber das war auch die letzte Version des AppBuilder (genannt Delphi)
Delphi-Quellcode:
Vor Delphi 2010 brauchte man z.B. sowas
var
I: IInterfaceComponentReference; O: TComponent; begin I := TComponent.Create(Self); O := TComponent.Create(Self); I := O as IInterfaceComponentReference; // nötig, wenn I z.B. nur IInterface wäre I := O; // hier wird das Interface der Variable genommen O := I as TComponent; // und bei Objekten ist alles die selbe Referenz, egal auf welche Klasse es gecastet wurde, aber bei I>O ist der Cast nur "explizit" möglich end;
Delphi-Quellcode:
IInterfaceComponentReference = interface
['{E28B1858-EC86-4559-8FCD-6B4F824151ED}'] function GetComponent: TComponent; end; function TComponent.IntfGetComponent: TComponent; // function IInterfaceComponentReference.GetComponent = IntfGetComponent; begin Result := Self; end; |
AW: gemischter Interface-/Objektzugriff
Zitat:
Dass Du die Methode Foo brauchst - ok. Aber dann auf die Objektinstanz zuzugreifen halte ich für falsch. Du könntest a) Foo auch auf das Interface geben. b) ein zweiters Interface machen Ich tendiere dazu Implementierungen von interfaces komplett zu verstecken und nur noch eine Fabrikmethode nach außen zu geben. |
AW: gemischter Interface-/Objektzugriff
Zitat:
Delphi-Quellcode:
und jetzt der Owner:
IFooItem = Interface
['{9995E78E-45DF-4C25-B657-7396738FEA70}'] procedure Bar; end; IFooFooItem =Interface ['{9995E78E-45DF-4C25-B657-7396738FEA70}'] procedure Foo(const AValue); end; TFooItem = class(TinterfacedObject, IFooItem, IFooFooItem) public procedure Bar; procedure Foo(const AValue); end;
Delphi-Quellcode:
Wie wird jetzt die Instanz von FItem gespeichert? Als einzigste Lösung würde mir wieder die ObjektInstanz einfallen und in den Get* Methoden dann ein GetInterface(IFooXItem, Result)aber dann habe ich wieder einen Zugriff auf die Objektinstanz!?!?
TFooOwner = class
private Fitem: XXXXX function GetItem: IFooItem public property Item: IFooItem getItem; property FooItem: IFooFooItem GetFooItem; end; |
AW: gemischter Interface-/Objektzugriff
Es gibt kurz gesagt, eigentlich drei wesentliche Gründe für den Einsatz von Interfaces unter Delphi:
- gleiche Funktionalität in unterschiedlichen Klassen (ohne gemeinsame Basisklasse) als Alternative zur nicht vorhandenen Mehrfachvererbung - Benutzung von Referenzzählung und automatischer Freigabe (wenn man das will) - evtl. Einbindung von DLLs Man erreicht eine abstrakte Beschreibung von Datenfeldern und Funktionen, ohne die genaue Implementation in den Klassen kennen zu müssen. In Deinem Bespiel erkenne ich nicht, warum Du in einem Fall plötzlich mit Interfaces arbeiten willst/musst. Werden ganz unterschiedliche Klassen an Deine Funktion übergeben? Den geringsten Umstellungsaufwand hast Du sicher mit dem Vorschlag von Uwe. Dann kannst Du einfach normal mit Deinen Objekten arbeiten und dieses einfach einmalig in Form eines Interfaces an die Funktion übergeben. Eine andere Möglichkeit wäre die Umstellung insgesamt auf Interfaces, das würde aber einiges an Mehraufwand und grundsätzlichen Änderungen mit sich bringen. Interfaces sind nützlich, aber man sollte abwägen, ob sie im vorliegenden Fall Vorteile bringen... |
AW: gemischter Interface-/Objektzugriff
Zitat:
- Decoupling des Codes, also keine Abhängigkeiten im Source ala Class1 kennt Class2 kennt Class3 die wieder Class1 kennt, etc.. Dadurch wird der Code auch besser Testbar. Wenn man dann noch hingeht und die Interfaces in die Klassen hineingibt, bekommt man schlanken wartbaren Code. |
AW: gemischter Interface-/Objektzugriff
Das kannst du aber auch mit abstakten Klassen erreichen.
Das extern Bekannte wird abstrakt definiert und deine Klasse1-3 leiten dann halt jeweils von sowas ab. siehe TStrings oder TStream |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 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