Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Lossy eX hat geschrieben:
In Pascal bedeuten Interfaces schon einen gehörigen Mehraufwand was das Schreiben von Code angeht. Und wenn dann muss man eigentlich auch komplett auf interfaces setzen, denn es ist potentiell ziemlich gefährlich Klasseninstanzen und Interfaces gleichzeitig zu benutzen, da man bei interfacebasierten Objekten nicht mitbekommt, wann es freigegeben wird. Also bei so etwas passiert es häufig, dass einem die Klasseninstanzen unter dem Hintern weggelöscht wird.
Meiner Meinung nach sollte man sich gut überlegen ob man Interfaces benutzt oder nicht (auch wenn die tierisch praktisch sind). Und wenn dann wäre es besser, wenn man schon ein paar Jahre mit normalem OOP gearbeitet hat.
Oh, dass wußte ich nicht. Ich bin von Java her den excessiven Umgang mit Interfaces bekannt.
Dann ist unter Delphi also die einzigste Möglichkeit mehrere Eigenschaften aus verschiedenen Strängen zu kombinieren (Mehrfachvererbung) nur für Fortgeschrittene verfügbar. Schade
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Zitat:
Dann ist unter Delphi also die einzigste Möglichkeit mehrere Eigenschaften aus verschiedenen Strängen zu kombinieren (Mehrfachvererbung) nur für Fortgeschrittene verfügbar. Schade
Na ja. Nur für Fortgeschrittene nun auch nicht. Ich denke in Java wird es auch so laufen, dass du irgendwo dein Interface definieren musst und dann entsprechend bei der ein oder anderen Klasse die Interfaces implementieren musst. Und da werden einige Sachen genau so laufen wie in Pascal.
Interfaces können zum Beispiel nicht auf Member zugreifen (was auch gut ist). Sondern es muss alles durch Methoden gelöst werden. Außerdem ist es in Pascal nicht ratsam Interfaces und die implementierende Klasse gleichzeitig zu benutzen. Da man sich sonst leicht die Instanz unter dem Hinter wegschießt. Entsprechend muss man dann diese Teile komplett mit Interfaces gestalten, da so etwas dann nicht passiert.
Wenn man dann allerdings dabei ist seine Objektstruktur zu entwickeln und häufiger mal etwas daran ändert, dann artet der Schreibaufwand mitunter leicht mal aus. Und das ist dann einfach nur nervig. Da bietet es sich einfach an, wenn man relativ genau weiß wie die Objektstruktur auszusehen hat und was sie können soll. Denn dann hält sich der Aufwand irgendwo noch in Grenzen.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Sorry, dass das jetzt hier zur Interface Diskussion wird, aber:
Lossy eX hat geschrieben:
Interfaces können zum Beispiel nicht auf Member zugreifen (was auch gut ist). Sondern es muss alles durch Methoden gelöst werden. Außerdem ist es in Pascal nicht ratsam Interfaces und die implementierende Klasse gleichzeitig zu benutzen. Da man sich sonst leicht die Instanz unter dem Hinter wegschießt. Entsprechend muss man dann diese Teile komplett mit Interfaces gestalten, da so etwas dann nicht passiert.
Wenn du damit meinst, dass durch die Benutzung der Implementierenden Klasse, das Interface selbst seinen Sinn verliert: Ja das ist in Java genauso. Ist quasi Prinzipbedingt. Wenn man wissentlich seine Kapselung durchbricht, dann brauch man auch gar keine Kapselung mehr nutzen. Im Grunde genommen deutet dies darauf hin, dass entweder das Design hinkt, oder aber das Interface erweitert werden muss.
Lossy eX hat geschrieben:
Wenn man dann allerdings dabei ist seine Objektstruktur zu entwickeln und häufiger mal etwas daran ändert, dann artet der Schreibaufwand mitunter leicht mal aus. Und das ist dann einfach nur nervig. Da bietet es sich einfach an, wenn man relativ genau weiß wie die Objektstruktur auszusehen hat und was sie können soll. Denn dann hält sich der Aufwand irgendwo noch in Grenzen.
Das ist nun wieder in Java dank Eclipse kein Problem. Derartige Änderungen werden durch das Refactoring gelöst. Das ist schnell und sauber. Der Code bleibt immer konsistent. Eigentlich müsste das in den neuen Delphi-Versionen auch so funktionieren. (Da war doch mal die Rede vom Refactoring. So vor 2 Jahren dachte ich.)
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Flash hat geschrieben:
Wenn du damit meinst, dass durch die Benutzung der Implementierenden Klasse, das Interface selbst seinen Sinn verliert: Ja das ist in Java genauso. Ist quasi Prinzipbedingt. Wenn man wissentlich seine Kapselung durchbricht, dann brauch man auch gar keine Kapselung mehr nutzen. Im Grunde genommen deutet dies darauf hin, dass entweder das Design hinkt, oder aber das Interface erweitert werden muss.
Ne ne. Ich meine nicht, dass die deren Sinn verliehrt (okay das auch). Aber wenn du eine Klasse erstellst, dann davon ein Interface erfragst und das Interface mit der Zuweisung von nil als nicht mehr benutzt "markierst", dann wird die Instanz gelöscht. Ob du sie noch benutzt oder nicht kann die Klasse nicht entscheiden. Und dann gehen Zugriffe auf die Instanz natürlich schief. Das muss aber auch nicht zwingend sein. Was dann passiert kann kaum jemand Vorraussagen.
Wie oder ob das mit dem Refractoring aussieht? Keine Ahnung. Möglich, dass es da etwas gibt. Aber damit kenne ich mich nicht so recht aus.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Lossy eX hat geschrieben:
Aber wenn du eine Klasse erstellst, dann davon ein Interface erfragst und das Interface mit der Zuweisung von nil als nicht mehr benutzt "markierst", dann wird die Instanz gelöscht. Ob du sie noch benutzt oder nicht kann die Klasse nicht entscheiden.
Ok... Das muss dann wirklich was Delphi spezifisches sein.
Solange du auf ein Objekt irgendwie zugreifen kannst, solange bleibt es in Java im Speicher. Wenn du es für den GarbageCollector freigeben willst, musst du alle Referenzen darauf auf "null" setzen.
Aber irgendwie kann ich mir den Fall den du beschreibst nicht wirklich vorstellen. Kannst du da mal ein minibeispiel posten?
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ich habe daraus mal ein neues Thema gemacht. Dann kann man auch ruhigen Gewissens intensiv drüber sprechen.
Aber ja Traude das Stimmt. Das was ich meine ist genau das Problem von Shaddow gewesen. Allerdings wird es da glaube ich nicht ganz so klar was genau das Problem ist. Deswegen werde ich das hier noch mal etwas ausholen.
Wenn man möchte, dass eine Klasse ein Interface unterstützt, dann muss man die Klasse von TInterfacedObject und den Interfaces ableiten. TInterfacedObject fügt eine automatische Referenzzählung zu der Klasse hinzu. Ähnlich wie bei Strings. Das Erstellen der Klasseninstanz erhöht diesen Zähler nur temporär (anschließend ist er wieder 0). Wenn du anschließend ein Interface erfragst und es benutzen möchtest, dann wird der Zähler erhöht. Wenn du es nicht mehr brauchst setzt du es nil. Damit wird der Zähler verringert. Und wenn dieser Zähler 0 erreicht hat, dann wird die Instanz gelöscht.
In Java ist es aber bedingt durch die GC so das alle Objekte eine Referenzzählung brauchen. In Pascal aber nicht. Da müssen die Klassen immer explizit per Hand freigegegen werden. Und wenn man da den Pointer einer Instanz 20 Mal kopiert spielt das keine Rolle. Interfaces stammen aber glaube ich von COM ab und dort ist es so, dass man ein Objekt anfordert und wenn man es nicht mehr benötigt, dann wird es nil gesetzt und verschwindet von der Bildfläche. Und an dieses Verhalten hält sich Pascal. Wäre irgendwie ja auch blöd, wenn man die Instanz dann totzdem noch mal explizit löschen müsste.
Als Beispiel mal folgendes. Interface und die implementierende Klasse. Was die Klasse genau macht tut nichts zur Sache.
Code:
type
IBlah =interface
procedure Blah;
end;
TBlah =class(TInterfacedObject, IBlah)
public
procedure Blah;
end;
Und jetzt benutzen wir das mal wie folgt.
Code:
var
Blah: TBlah;
BlahI: IBlah;
begin
Blah := TBlah.Create();// Instanz erstellen
BlahI := Blah;// Das Interface IBlah erfragen
BlahI.Blah;// Funktion aufrufen
BlahI :=nil;// hierbei erriecht der Zähler wieder 0
Blah.Blah;// hier wird es höchstwahrscheinlich knallen
Klassisch müsste das aber eher so aussehen.
Code:
var
Blah: IBlah;
begin
Blah := TBlah.Create();
Blah.Blah;
Blah :=nil;
Man könnte die Referenzzählung zwar auch beeinflussen in dem man selber _AddRef und _Release aufruft um eben vorzuteuschen, dass davon ein Interface benutzt würde. Allerdings sollte man dann aber schon ziemlich genau wissen was da passiert und was man da eigentlich tut.
Das mit dem automatischem Freigeben ist wirklich ne sache an die man sich erst gewöhnen muß (und mit der ich mir schon so oft ins Knie geschossen hab). Kann man aber u.a. auch damit umgehen das man dort wo die Klasse (die das Interface implementiert) erstellt wird auch direkt nen pointer auf das Interface zieht. Dieser pointer wird jedoch nicht weiter benutzt bzw. weitergegeben. D.h. selbst wenn später alle sonstwoher kommenden anderen pointer auf das Interface nil sind gibt es immernoch diesen einen "ur" pointer. Den kann man dann halt "selber" nil setzen wenn man die Klasse wirklich weg haben will.
Bin selber auch noch relativ neu in der Interface Programmierung,
aber insgesammt gefallen mir die zusätzlichen Möglichkeiten enorm.
Problem ist nur das man es erstmal richtig verstehen und anwenden muß
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2068
Programmiersprache: C++
Wie geht ihr denn mit der Restriktion um, dass Interfaces keine Variablen sondern nur Funktionen/Proceduren zur Verfügung stellen?
Bei meinem Versuch bzgl. Interfaces ist es an der Stelle gescheitert.
So wie in Java auch - in Interfaces implementiere ich keine Funktionen,
dafür gibt es Klassen. Und wenn ich dann doch mal
eine Funktion habe die in 90% der Fälle gleich aussieht
mach ich mir eine abstrakte Klasse, die das Interface implementiert
und leite die ab.
_________________ Bevor du definierst, was etwas ist, versichere dich seiner Existenz.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Billi: Nur zum Verständniss. Das klingt so als ob du eine Klasse erstellst und davon dann immer wieder ein Interface erfragst und es recht schnell wieder verwirfst? Und das tust du immer von der Klasseninstanz aus. Sehe ich das Richtig? Wenn nein vergiss das darunter.
Du kannst in dem oben beschriebenen Fall natürlich auch nur das Interface speichern. Das sollte auch gehen, wenn die Klasse verschiedene Interfaces unterstützt. Ich meine du kannst ein Interface auch fragen ob die Klasse dahinter auch noch andere Interfaces unterstützt. Wobei das Hauptinterface natürlich schon auch irgendwelche sinnvollen Funktionalitäten bieten sollte. Das einfach nur leer zu lassen um ein Interface zu haben würde zwar gehen halte ich persönlich aber nicht unbedingt für den besten Weg. Dann sollte man schauen ob das gewählte Design so das Beste war.
Interface und Variablen: Jepp. Das Interface dient nur dazu um eine Schnittstelle zu definieren. Entsprechend kannst du auch nur öffentliche Methoden und Eigenschaften definieren. Die Eigenschaften können aber auch nur auf die Methoden zugreifen. So etwas wie bei einer Klasse, dass eine Eigenschaft direkt auf eine Membervariable zugreift geht nicht. Es sind immer nur Get oder Set-Methoden. Selbst für eine kleine ReadOnly Eigenschaft. Das ist leider auch ein Punkt der bei Interfaces dazu führt, dass man recht schnell reichlich Code zusammen bekommt. Dabei hilft leider nur, dass man sich vorher gut überlegen sollte was man wirklich braucht und was nicht. Aber dafür müssen die Eigenschaften auch nur beim Interface definiert werden.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Wenn ich mir das Beispiel so angucke, dann ist genau das eingetreten, was Interfaces wieder durchlöchert.
Damit das Beispiel nämlich funktionieren kann, ist beides - das Interface und die eigentliche Klasse - nämlich bekannt.
Wirklich Sinn machen Interfaces aber an den Stellen, wo man nur mit ihnen Arbeitet und nicht mit den tatsächlich implementierenden Klassen.
Um das abzukapseln sollte man eine Factory-Klasse irgendwo haben.
Nur diese Factory verwendet die eigentliche implementierende Klasse. Nach außen liefert sie immer nur "Instanzen" (bzw. Implementierungen) des Interface.
Außerhalb der Factory kann es also dann gar nicht mehr zu dem besagten Fehler kommen.
Und wenn dann noch direkt mit "IBlah := TBlah.Create();" gearbeitet wird, schwirrt sowieso keine Variable von TBlah mehr herum, sondern nur noch Interface-Variablen.
Ich gebe aber zu, dass das in Delphi durchaus nicht so sorgenfrei implementiert ist, wie in Java. Dort wird, wie richtig angemerkt, sowieso überall Referenzen gezählt und eine NullPointer-Exception kann deshalb nur dort fliegen wo expliziet eine Variable Null gesetzt wurde.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Flash hat geschrieben:
Damit das Beispiel nämlich funktionieren kann, ist beides - das Interface und die eigentliche Klasse - nämlich bekannt.
Genau. Das Beispiel. Du musst auf irgendeine Art und Weise eine Instanz der Klasse erstellen. Normalerweise würde das dann in einer exportierten Methode einer DLL passieren oder über COM. Was aber auch irgendwie wieder auf eine Methode einer DLL hinaus läuft. Also irgendwie gekappselt. In dem Beispiel habe ich es nur so gemacht, dass ich eben die Instanz direkt erstellt habe. Der Entwickler sieht die Klasse TBlah normalerweise aber nicht. So sollte es zu mindest sein.
Und zu allem Anderen. Das habe ich ja gesagt. Nur erfordert es eben, dass man Interfaces komplett durchzieht. Also das man für alles was man irgendwo benutzt dann eben ein Interface implementiert. Und das ist mitunter ziemlich viel mehraufwand. Vor allem, wenn man sich seiner Struktur noch nicht 100%tig sicher ist.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Super. Damit sind wir uns einig. Aber schön das mal ausdiskutiert zu haben.
Für alle, die jetzt neugierig auf Interfaces werden, am besten mal nach nem Tutorial in eurer Sprache suchen.
Ein großer Vorteil von Interfaces ist (das wurde noch nicht angesprochen), dass man Packete austauschen kann.
Angenommen man hat ein Paket (sowas gibts in Delphi jetzt nicht. Am ehesten gilt das für DLLs), das Klassen enthält, die ein bestimmtes Interface implementieren. Im Hauptprogramm ist das Interface bekannt (nicht die Klasse die in der DLL das Interface implementiert.).
Über eine Factorymethode läßt man sich aus der DLL nun eine Instanz liefern, die das Interface implementiert. Super soweit. Man kann jetzt aber z.B. die DLL (oder das Package) austauschen, ohne, dass das Hauptprogramm angepasst werden muss, solange es wieder eine Factorymethode gibt, die eine Implementation des Interfaces liefert.
Solche dynamischen Sachen sind z.B. für Pluginschnittstellen ziemlich geil.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Lossy, Ich weiß grad selber nicht mehr so genau was das Problem war und was ich genau mache. Hab das eventuell auch falsch in erinnerung (Bin grad auf Programmier Pause und hab schon über nen Monat nicht mehr dran gearbeitet). Muß ich demnächst mal wieder in den Code schauen...
Wofür ich interfaces grad benutze ist ein Plugin System auf DLL Basis. Jedes Plugin exportiert dabei ein Interface über das es komplett gesteuert werden kann. Aber gleichzeitig erzeugt die Host Anwendung auch diverse Interfaces die an die Plugins übergeben werden. So wird mein komplettes Skin System per Interface an die Plugins übergeben. Vorteil ist das nur die Host Anwendung das gesammte Skin System einmalig laden muß und dann den Plugins per Interface Zugriff auf die Skin Manager Klasse erteilt. Die Möglichkeiten sind hier wirklich enorm da man praktisch uneingeschränkten Datenaustausch zwischen DLL/Plugin und Anwendung realisieren kann. Ohne Interfaces mußte vorher jedes Plugin das komplette Skin System (mit allen Klassen) selber erstellen und laden.
Sehr Komfortabel ist hier auch die Möglichkeit verschiedene Interface beliebig in der implementierende Klasse zu kombinieren. So kann man sich bei einem Plugin System verschiede Interfaces bauen die bestimmte funktionalitäten darstellen. Soll das plugin nur Funktion A beinhalten so wird nur Interface A implementiert. Soll es noch B haben dann werden einfach Interface A und B implementiert. Die Anwendung die das Plugin dann über das Interface steuert kann einfach nachprüfen welche Interfaces (A?, A und B?, B?) implementiert wurde.
Für Plugin Systeme wirklich eine geniale Geschichte
Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.