![]() |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hallo!
Ich habe es jetzt mit der Idee mit den Interfaces von rantaplan gemach. Ohne, dass ich eine "Unit3" benötige. Trotzdem würde mich interessieren, wie dizzys Lösung dieses Problem umschifft; ich habe das folgende Beispiel doch genau so gemacht, wie es gedacht ist mit der zusätzlichen Unit, oder?
Delphi-Quellcode:
unit Unit1;
interface uses Unit3; implementation procedure TClass1.DoOneThing(Class2: TClass2); begin // I'm really busy end; end.
Delphi-Quellcode:
unit Unit2;
interface uses Unit3; implementation procedure TClass2.DoAnotherThing(Class1: TClass1); begin // That's too much for me end; end.
Delphi-Quellcode:
Jetzt meckert der Compiler wegen ungenügenden Forward- oder External-Deklarationen in Unit3 - Logisch, die Implementierun findet ja in den ursprünglichen Units statt. Trotzdem wurde das Problem von niemandem hier erwähnt. Wenn ich nun im implementation-Teil von Unit3 ein Uses auf die ursprünglichen Units setze:
unit Unit3;
interface type // Forward-deklarationen aller Klassen TClass1 = class; TClass2 = class; // Vollständige Deklaration Class 1 TClass1 = class private // Verweis auf Class 2 Class2: TClass2; public // Irgendeine Methode procedure DoOneThing(Class2: TClass2); end; // Vollständige Deklaration Class 2 TClass2 = class private // Verweis auf Class 1 Class1: TClass1; public // Irgendeine Methode procedure DoAnotherThing(Class1: TClass1); end; implementation end.
Delphi-Quellcode:
kommt der Fehler natürlich nicht mehr, jedoch mag der Compiler nun in den ursprünglichen Units die Implementierungen nicht mehr - was ich nicht nachvollziehen kann.
implementation
uses Unit1, Unit2; end. Ob der Kreuzbezug richtig ist oder nicht möchte ich hier nicht zur Diskussion stellen - ich schließe mich da der Meinung von BenBe an. dartrax |
Re: Trick um "überkreuzenden Bezug" von Units zu u
hier noch eine moeglichkeit mit interface
Delphi-Quellcode:
dann die beiden implementierunsklassen
unit UInterfaces;
interface type IKlasse1 = interface function tellName(): string; function doSomething(): string; end; IKlasse2 = interface function tellName(): string; function doSomething(): string; end; implementation end. Klasse 1
Delphi-Quellcode:
Klasse 2
unit UKlasse1;
interface uses ComObj, UInterfaces; type TKlasse1 = class(TComObject, IKlasse1) public InterfaceZurKlasse2: IKlasse2; function tellName(): string; function doSomething(): string; constructor Create; end; implementation constructor TKlasse1.Create(); begin end; function TKlasse1.tellName(): string; begin Result := 'Bin Klasse1'; end; function TKlasse1.doSomething(): string; begin Result := 'Bin in Klasse1 und rufe jetzt Klasse2 auf: '; if not(InterfaceZurKlasse2 = nil) then Result := Result + InterfaceZurKlasse2.tellName() else Result := Result + 'Ups, nix da!!'; end; end.
Delphi-Quellcode:
und die anwendung
unit UKlasse2;
interface uses ComObj, UInterfaces; type TKlasse2 = class(TComObject, IKlasse2) public InterfaceZurKlasse1: IKlasse1; function tellName(): string; function doSomething(): string; constructor Create; end; implementation constructor TKlasse2.Create(); begin end; function TKlasse2.tellName(): string; begin Result := 'Bin Klasse2'; end; function TKlasse2.doSomething(): string; begin Result := 'Bin in Klasse2 und rufe jetzt Klasse1 auf: '; if not(InterfaceZurKlasse1 = nil) then Result := Result + InterfaceZurKlasse1.tellName() else Result := Result + 'Ups, nix da!!'; end; end.
Delphi-Quellcode:
so ungefaehr eben ;o)
unit UMain;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UKlasse1, UKlasse2, UInterfaces, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var Klasse1: TKlasse1; Klasse2: TKlasse2; InterfaceKlasse1: IKlasse1; InterfaceKlasse2: IKlasse2; begin Klasse1 := TKlasse1.Create(); Klasse2 := TKlasse2.Create(); Klasse1.InterfaceZurKlasse2 := Klasse2; Klasse2.InterfaceZurKlasse1 := Klasse1; Memo1.Clear(); Memo1.Lines.Add(Klasse1.doSomething()); Memo1.Lines.Add(Klasse2.doSomething()); end; end. |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Einfacher ist in dem Moment relativ. Ich persönlich finde es grob unsauber und unhadlich wenn:
Einfach mal einen Blick in Classes.pas werfen. Dann sieht man sehr schnell wie einfach man sich mit Forward declares beide Hände fesselt und die Units ins grenzenlose wachsen lassen. :roll: Nobodys Weg zeigt absolut in die richtige Richtung. Zwei Möglichkeiten dazu findet man hier: ![]() @Nobody, statt TComObject wären TInterfacedObject, TContainerObject oder TAggregatedObject bessere Basisklassen für die Implementierung von Interfaces. ;) (Außerdem werden sie schon in System deklariert :) ) |
Re: Trick um "überkreuzenden Bezug" von Units zu u
@robert: hab schon lange nicht mehr in delphi entwickelt, deswegen hab ich das erstbeste genommen. hast aber recht :o)
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Zitat:
Die VCL enthält meiner Meinung nach fast keine OOP Designschwächen in ihrer Klassenhierarchie. Gruß hagen |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zum ursprünglichen Problem:
Zitat:
Nachdem ich heute die neue Version von ![]() Wie wäre es mit Chrome? Das kennt diese Probleme dank eines modernen Compilers nicht mehr. Im Gegensatz zu Delphi.Net kann man in Chrome namespaces so verwenden wie sie gedacht waren. (Und muss sich nicht weiterhin mit Dateinamen nerven lassen :wall: ) Die Dateinamen sind absolut unerheblich ;) Erste Datei:
Delphi-Quellcode:
Zweite Datei:
namespace EinNamespace;
interface type Class1 = public class private fClass2 :Class2; public property Class2 :Class2 read fClass2; end; implementation end.
Delphi-Quellcode:
Beide Klassen sind im gleichen Namespace deklariert und man muss rein gar nichts rumbasteln, rumschrauben oder sonstwas umbiegen.
namespace EinNamespace;
interface type Class2 = public class private fClass1: Class1; public property Class1 :Class1 read fClass1; end; implementation end. Ich meine genau so sollte es doch sein. :) Sicher ist es in solchen Fällen oftmals handlicher gewisse Abstraktionen auf das Wesentliche zu machen. Aber wenn man es macht, dann nur weil man es will, nicht weil der Compiler zu antiquiert ist. ;) *Ich fand es übrigens so gut, dass ich es nach 15 Minuten testen gleich gekauft habe. Nach all den Face lifts seit meiner vorherigen ur-alt-beta Version erscheint mir Chrome sogar mächtiger als C#, hat alle IMHO sinnlosen Beschränkungen von Delphi über Board geworfen. Aber trotzdem diese schlichte Eleganz bewahrt, die Pascal auszeichnet... |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hi Robert,
Chrome werde ich mir bei Gelegenheit mal angucken. Ich habe zwar die Vorzüge von .NET erkannt, bin aber noch nicht umgestiegen :-) im Moment wäre das zuviel Arbeit. ABER, was die Sache mit den Überkreuzdeklarationen angeht, habe ich mich entschlossen, den Entwurf überhaupt nicht weiterhin so gestalten zu wollen. Strebe jetzt strenge Baumhierarchien von OBEN nach UNTEN an. Gegenseitige Objektbekanntschaften vermeide ich, indem ich die Kommunikation von UNTEN nach OBEN ganz normal über Objektreferenzen löse, aber umgekehrt von OBEN nach UNTEN nur noch versuche EVENTS zu nutzen. Somit müssen die Klassen, die in der "Hierarchie" oben stehen, überhaupt keine Objectreferenz mehr haben. Damit entfällt auch das Problem der Überkreuzdeklaration. Ausserdem auch viel besser wegen Quelltextwiederverwendbarkeit, gegenseitige Abhängigkeiten und so theoretischen Zeugs ;-) Und wenn ichs in Notfällen wirklich mal brauche, werde ich weiterhin rumcasten :-D bis denn dann |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:17 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