Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#5

Re: Zyklusproblem ( Circular reference )

  Alt 23. Apr 2007, 07:27
Reinhards Vorschläge sind erstmal grundsätzlich korrekt, bis auf Kleinigkeiten:
Zitat von Reinhard Kern:
2. Funktionen ... werden ... ausgelagert in eigene Units, ... Diese Units werden in der Main-Unit als uses meist im Interface deklariert, da ..
Wenn Du die Unit im Interface-Abschnitz der Hauptunit gar nicht verwendest, dann solltest Du die Unit auch erst im Uses-Abschnitt der Implementation angeben. So vermeidet man von vorneherein fast immer eine zirkuläre Referenz.
Delphi-Quellcode:
Unit A;
Interface
Uses UnitB; // deklariert TTypeB, die aber im Interfaceabschnitt gar nicht verwendet wird ...
Implementation
Procedure Foo;
Var
  b : TTypeB; // ... sondern erst hier
...
Ist nicht korrekt, aber
Delphi-Quellcode:
Unit A;
Interface
Implementation
Uses UnitB; // Hier gehörts hin.
Procedure Foo;
Var
  b : TTypeB;
...
ist perfekt.

Grundsätzlich gilt;
Deklarationsreferenzen (Uses, Var) sollten so nah wie möglich an der ersten Verwendung verschoben werden. C# und Java z.B. gehen ja bezüglich der Variablen so weit, das man die erst unmittelbar in dem Codeblock deklariert, in dem sie verwendet wird; Delphi leider nicht.

Wenn nun einmal eine Unit A im Interface-Abschnitt etwas aus Unit B benötigt, und umgekehrt, dann kann man das in eine dritte Unit C auslagern.
Das ist, was Reinhard im Punkt 3. ansprichst.

Hier mal ein Beispiel;
Delphi-Quellcode:
Unit UnitA;
Interface
Uses UnitB;
Type
  TTypeA = Class
    fB : TTypeB
  End;
....

Unit UnitB;
Interface
Uses UnitA;
Type
  TTypeB = Class
    fA : TTypeA;
  End;
Eine zirkuläre Referenz, die sich durch o.g. Regeln nicht auflösen lässt.
Hier kannst Du z.B. die Deklaration von TTypeA und TTypeB in eine separate Unit auslagern (Reinhards Vorschlag). Wenn nun aber die Units eigentlich nur diese eine Klasse deklarieren und implementieren, würde das natürlich den Konflikt auflösen, wäre aber u.U. bezüglich der Übersichtlichkeit kontraproduktiv.

Hier würde ich erstmal nachdenken, was diese zirkuläre Referenz bedeutet: Wenn Du keinen Designfehler gemacht hast, bedeutet das, das wir es hier mit zwei voneinander abhängigen Klassen zu tun haben, die dann aber auch wirklich ein eine Unit gehören: Die Übersichtlichkeit würde eigentlich erhöht, da 'zusammenwächst, was zusammengehört'.

Wem das dann doch zu unübersichtlich wird, der deklariert z.B. abstrakte Vorfahren von A und B in einer Hilfsunit:
Delphi-Quellcode:
Unit ABTypes;
Interface
Type
  TAbstractTypeA = Class
   <Abstrakte Deklaration der Klasse>
  End;
  TAbstractTypeB = Class
   <Abstrakte Deklaration der Klasse>
  End;
End.
Unit A greift nun auf ABTypes zu und definiert 'fB' als 'TAbstractTypeB'. Zirkuläre Referenz aufglöst, Übersichtlichkeit und Dateistruktur erhalten.
Delphi-Quellcode:
Unit UnitA;
Interface
Uses ABTypes;
Type
  TTypeA = Class
    fB : TAbstractTypeB
  End;
Hier gibt es keine Vorschrift: Einzig und allein das 'Design' sowie das Datenstrukturlayout zählen.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat