Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Trick um "überkreuzenden Bezug" von Units zu umgehen ? (https://www.delphipraxis.net/31171-trick-um-ueberkreuzenden-bezug-von-units-zu-umgehen.html)

dartrax 5. Mai 2005 15:18

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:
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.
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:
Delphi-Quellcode:
implementation

uses Unit1, Unit2;

end.
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.

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

n0b0dy@home 5. Mai 2005 19:13

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
hier noch eine moeglichkeit mit interface

Delphi-Quellcode:
unit UInterfaces;

interface

type

  IKlasse1 = interface
    function tellName(): string;
    function doSomething(): string;
  end;

  IKlasse2 = interface
    function tellName(): string;
    function doSomething(): string;
  end;

implementation

end.
dann die beiden implementierunsklassen

Klasse 1
Delphi-Quellcode:
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.
Klasse 2
Delphi-Quellcode:
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.
und die anwendung
Delphi-Quellcode:
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.
so ungefaehr eben ;o)

Robert_G 5. Mai 2005 19:29

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
Zitat:

Zitat von BenBE
Einfachste und sauberste Lösung:

Forward-Deklaration von TClass2
Deklaration von TClass1
Deklaration von TClass2

Alles in eine Unit packen.

Anders geht's nicht!

Es geht anders, einfacher und sauberer!
Einfacher ist in dem Moment relativ.
Ich persönlich finde es grob unsauber und unhadlich wenn:
  • mich eine Klasse, zwingt eine andere in der gleichen Unit zu deklarieren
  • ich auch immer diese zweite Klasse überall mitscheleifen muss, wo Klasse1 benutzt wird
  • Interface und Implemetierung im Chaos untergehen

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: http://www.delphipraxis.net/internal...=359178#359178

@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 :) )

n0b0dy@home 5. Mai 2005 20:30

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)

Robert_G 5. Mai 2005 20:33

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
Zitat:

Zitat von n0b0dy@home
@robert: hab schon lange nicht mehr in delphi entwickelt, deswegen hab ich das erstbeste genommen. hast aber recht :o)

Wie gesagt: Du lagst (, bis auf TComObject, ) absolut richtig. ;)

negaH 6. Mai 2005 09:47

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
Zitat:

naja, das ganze laesst aber auf einen design-fehler schliessen, wenn ich einen kreuzbezug erzeuge. es wuerde mich schon interessieren, warum er hier von noeten ist.
Sehe ich auch so. Baue die beiden überkreuzenden Klassen in eine 3. Unit ein, aber als abstrakte Basisiklassen. In den anderen 2 Units leitest du nun von diesen beiden Basisklassen die implementierenden Klassen ab. Wenn du das clever anstellst wirst du absolut ohne Typcast und der gleichen auskommen.

Zitat:

Dann wär die VCL ein einziger Designfehler: Dort wird in TControl bereits auf TWinControl verwiesen, und ähnliches.
Nein, dieser Vergleich ist schlicht falsch. Es gibt einen definitiven Designunterschied in der Hierarchie von TWinControl und TControl. Denn ein TControl kann niemals ein Parent eines TWinControls sein, und alleine diese Design-Richtlinie bedingt das sich die fast komplette Schnittstelle in den relevanten Teilen von TControl und TWinControl unterscheiden. Es wäre ohne größeren Aufwand durchaus möglich TControl und TWinControl in separate Units auszulagern. Nur, da es beides im Grunde "abstrakte" Klassen sind mit gleichem Designbezug wäre dies ziemlich kontraproduktiv.

Die VCL enthält meiner Meinung nach fast keine OOP Designschwächen in ihrer Klassenhierarchie.

Gruß hagen

n0b0dy@home 6. Mai 2005 12:42

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
Zitat:

Sehe ich auch so. Baue die beiden überkreuzenden Klassen in eine 3. Unit ein, aber als abstrakte Basisiklassen. In den anderen 2 Units leitest du nun von diesen beiden Basisklassen die implementierenden Klassen ab. Wenn du das clever anstellst wirst du absolut ohne Typcast und der gleichen auskommen.
auch eine moeglichkeit. nur bei verteilten anwendungen wird es dann wieder eng. aber wenn die sache in einer anwendung bleibt, ist es sicher die einfacherere loesung (wuerde sie auch bevorzugen).

Robert_G 7. Mai 2005 01:45

Re: Trick um "überkreuzenden Bezug" von Units zu u
 
Zum ursprünglichen Problem:
Zitat:

Zitat von stoxx
kennt irgendjemand eine clevere Möglichkeit um nicht Haufen Umwege gehen zu müssen ?
Ich habe zwei Objecte in zwei verschiedenen Units.
Und will von jedem Object einen Zeiger auf das andere Object speichern können.

in Unit1:

Code:
TClass1 = class

 p : TClass2;

end;
in Unit2:

Code:
TClass2 = class

 p : TClass1;

end;
dummerweise muss ich nun in Unit2 die Unit1 in den Uses Klauseln einfügen und umgekehrt.
Dummerweise kommt ja nun die Meldung "Überkreuzender Bezug zweier Units"
HAb schon einige ZEit gegrübelt, kann man das irgendwie über eine dritte Unit umgehen ?

Die effektivste Umgehung des Problems dürfte es wohl sein, das Problem GANZ aus der Welt zu schaffen. ;)
Nachdem ich heute die neue Version von Chrome getestet habe* und da stoxx mittlerweile auch das .Net Framework entdeckt hat...

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:
namespace EinNamespace;

interface

type
  Class1 = public class
  private
      fClass2 :Class2;
   public
      property Class2 :Class2 read fClass2;
  end;
 
implementation

end.
Zweite Datei:
Delphi-Quellcode:
namespace EinNamespace;

interface

type
  Class2 = public class
  private
      fClass1: Class1;
  public
      property Class1 :Class1 read fClass1;
  end;
 
implementation

end.
Beide Klassen sind im gleichen Namespace deklariert und man muss rein gar nichts rumbasteln, rumschrauben oder sonstwas umbiegen.
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...

stoxx 8. Mai 2005 13:16

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.
Seite 3 von 3     123   

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