Frage

    

Diese Frage bereits eine Antwort hier:

         

Gibt es eine Möglichkeit der Fortbewegung Kreis Einheit Referenzen in Delphi?

Vielleicht eine neuere Version von delphi oder etwas Magie Hack oder etwas?

Mein delphi Projekt hat 100 000 + Zeilen Code meist auf Singleton-Klassen basieren. Ich muss das Refactoring, aber das mehrere Monate der „zirkulären Referenz“ Hölle :)

bedeuten würde
War es hilfreich?

Lösung

Ich habe eine Million Zeilen von Legacy-Code für die letzten 10 Jahre Aufrechterhaltung der Nähe, damit ich Ihren Schmerz verstehen!

Im Code, dass ich bleibe, wenn ich Kreis Nutzungen erlebt habe, habe ich oft festgestellt, dass sie durch Konstanten oder Typdefinitionen in der Einheit A verursacht werden, die durch die Einheit B. benötigt werden (Manchmal ist es auch ein kleines Stück Code (oder sogar globale Variablen) in Einheit A, die auch durch die Einheit B benötigt wird.

In dieser Situation (wenn ich Glück!) Kann ich sorgfältig die Teile des Codes in eine neue Einheit C extrahieren, die die Konstanten enthalten, Typdefinitionen und gemeinsamen Code. Dann Einheiten A und B Verwendung Einheit C.

Ich poste die oben mit einem gewissen Zögern, weil ich kein Experte für Software-Design bin und erkennen, gibt es hier viele andere, die weit mehr Wissen sind als ich. Hoffentlich aber meine Erfahrung werden Sie von Nutzen sein.

Andere Tipps

  1. Es scheint, Sie haben ziemlich ernst Code Design-Fragen. Neben vielen Anzeichen für solche Fragen, die man die Einheit zirkuläre Referenzen. Aber wie Sie gesagt haben -. Sie können nicht alle den Code Refactoring
  2. alle bewegen, was zu UMSETZUNG Abschnitt möglich ist. Sie dürfen zirkuläre Referenzen haben.
  3. Zur Vereinfachung der Aufgabe (2), können Sie 3D-Party-Tools verwenden. Ich würde empfehlen - Peganza Pascal Analyzer ( http://www.peganza.com ). Es wird vorschlagen, was Sie für die Umsetzung Abschnitt bewegen kann. Wie werden Sie viel mehr Hinweise geben Ihren Code-Qualität zu verbessern.

Mit der Implementierung Abschnitt verwendet, wann immer möglich, und begrenzt, was in der Schnittstelle uses-Klausel ist zu dem, was hat in den Interface-Deklarationen sichtbar sein.

Es gibt keinen "magischen Hack". Zirkuläre Referenzen würde eine Endlosschleife für den Compiler verursachen (Einheit A erfordert Einheit B Kompilieren die Einheit A erfordert die Erstellung, die Einheit B erfordert Kompilieren, etc.).

Wenn Sie eine bestimmte Instanz, wo Sie denken, dass Sie nicht zirkuläre Referenzen vermeiden, bearbeiten Sie Ihre Post und geben Sie den Code; Ich bin sicher, dass jemand hier kann Ihnen helfen, herauszufinden, wie es behoben.

Es gibt viele Möglichkeiten, um zirkuläre Verweise zu vermeiden.

  1. Die Delegierten. Viel zu oft wird ein Objekt einen Code auszuführen, anstatt in einem Fall getan werden sollte, als sich durch das Objekt durchgeführt wird. Sei es, weil der Programmierer an dem Projekt arbeiten auf Zeit zu kurz war (sind wir nicht immer?), Hatte nicht genug Erfahrung / Wissen oder war einfach nur faul, einige Code wie diesen schließlich in Anwendungen enden. Reale Welt exemple. TCPSocket Komponente, die direkt eine visuelle Komponente der Mainform auf der Anwendung aktualisieren, anstatt die Hauptform eine „OnTCPActivity“ -Verfahren auf der Komponente registriert von

  2. Abstrakte Klassen / Interfaces. Mit einem von ihnen erlaubt eine direkte Abhängigkeit zwischen vielen Einheiten zu entfernen. Eine abstrakte Klasse oder eine Schnittstelle kann in einer eigenen Einheit erklärt allein verwendet wird, Abhängigkeiten zu einem Maximum zu begrenzen. Exemple: Unsere Anwendung verfügt über eine Debug-Form. Es hat Anwendungen auf so ziemlich die gesamte Anwendung, da sie Informationen aus verschiedenen Bereich der Anwendung anzeigt. Noch schlimmer ist, jede Form, die die Debug-Form zu zeigen, ermöglicht es auch auch am Ende erfordern alle Einheiten aus der Debug-Form. Ein besserer Ansatz wäre, eine Debug-Form zu haben, die im Wesentlichen leer ist, aber das hat die Fähigkeit zu registrieren „DebugFrames“.

    TDebugFrm.RegisterDebugFrame (Frame: TDebugFrame);

    Auf diese Weise hat die TDebugFrm keine Abhängigkeiten seines eigenen (außer als auf der TDebugFrame Klasse). Jedwedes Einheit, die die Debug-Form zu zeigen, erfordert, kann dies tun, ohne zu riskieren, entweder zu viele Abhängigkeiten hinzuzufügen.

Es gibt viele andere exemple ... Ich wette, es ein eigenes Buch füllen könnte. eine saubere Klassenhierarchie in einer Zeit effiziente Art und Weise zu entwerfen ist ziemlich schwer zu tun, und es kommt mit der Erfahrung. die Werkzeuge zur Verfügung, zu wissen, um es zu erreichen und wie sie zu benutzen ist der erste Schritt, um es zu erreichen. Aber um Ihre Frage zu beantworten ... Es gibt keine 1-size-fit-all Antwort auf Ihre Frage, es ist immer von Fall zu Fall getroffen werden.

ähnliche Frage: Delphi Unternehmen : wie kann ich das Besuchermuster ohne zirkuläre Referenzen

anwenden

Die Lösung präsentiert von Uwe Raabe nutzt Schnittstellen, um die zyklische Abhängigkeit zu lösen.

Modelliert Code-Explorer einen wirklich schönen Assistent hat alle für die Auflistung der Anwendungen einschließlich Zyklen.

Es setzt voraus, dass Ihr Projekt kompiliert wird.

Ich stimme mit den anderen Plakaten, dass es sich um ein Design-Problem ist.
Sie sollten sorgfältig auf Ihrem Design aussehen und nicht benutzte Geräte entfernen.

Bei DelphiLive'09, ich habe eine Sitzung mit dem Titel Smarter Code mit Datenbanken und Datensensitive Steuerelemente was ziemlich paar Tipps auf gutes Design enthält (nicht auf DB apps begrenzt).

- jeroen

Ich fand eine Lösung, die nicht die Verwendung von Schnittstellen benötigt, kann aber nicht alle Probleme der Kreisreferenz lösen.

Ich habe zwei Klassen in zwei Einheiten:. TMap und TTile

TMap Karte enthält und zeigt sie mit isometrischen Fliesen (TTile).

Ich wollte einen Zeiger in TTile habe auf der Karte zu Punkt zurück. Karte ist eine Klasse Eigenschaft TTile.

  

Klasse Var FoMap: TObject;

Normaly, müssen Sie jede entsprechende Einheit in der anderen Einheit erklären ... und die zirkuläre Referenz erhalten.

Hier, wie ich es umgehen.

In TTile, I declare Karte ein TObject und bewegen Map Einheit in der uses-Klausel des Einführungsabschnittes sein.

So kann ich Karte aber Bedarf kann sie jedes Mal zu TMap werfen seinen Eigenschaften zugreifen zu können.

Kann ich besser machen? Wenn ich könnte eine Getter-Funktion verwenden, um Typ es gegossen. Aber ich werde Verwendet Karte im Interface-Abschnitt zu bewegen brauche .... also, wieder auf Platz eins.

Im Einführungsabschnitt, habe ich eine Getter-Funktion deklariert, die nicht Teil meiner Klasse ist. Eine einfache Funktion.

  

Die Umsetzung

     

Verwendet Karte;

     

Funktionskarte: TMap;   Start     Ergebnis: = TMap (TTile.Map);   Ende;

Cool, dachte ich. Nun muß jedes Mal, wenn ich eine Eigenschaft meiner Karte nennen, ich habe gerade Map.MyProperty verwenden.

Ouch! Hat die Kompilierung! :) Haben Sie nicht die erwartete Art und Weise arbeiten. Der Compiler die Karte Eigenschaft TTile verwenden und nicht meine Funktion.

Also, ich meine Funktion aMap umbenennen. Aber meine Muse sprach mit mir. NOOOOO! Benennen Sie die Klasseneigenschaft zu aMap ... Jetzt kann ich Karte so, wie ich es intented.

Map.Size; Dieser Aufruf meine kleine Funktion, die Typumwandlung aMap als TMap;

Patrick Wald

gab ich eine frühere Antwort, aber nach einigen Denken und Kratzen fand ich einen besseren Weg, um das kreisförmige Referenz Problem zu lösen. Hier ist meine erste Einheit, die einen Zeiger auf einem Objekt TB müssen definieren, in Einheit B.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, b, StdCtrls;

type

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }

  public
    { Public declarations }
    FoB: TB;
  end;

var
  Form1: TForm1;



implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  FoB := TB.Create(Self);
  showmessage(FoB.owner.name);
end;

end.

Hier ist der Code der Einheit B, wo TB einen Zeiger auf TForm1 hat.

unit B;

interface

  Uses
    dialogs, Forms;

  type
    TForm1 = class(TForm);

    TB = class
     private
       FaOwner: TForm1;
     public
       constructor Create(aOwner: TForm);
       property owner: TForm1 read FaOwner;
    end;

implementation
  uses unit1;

  Constructor TB.create(aOwner: TForm);
  Begin
    FaOwner := TForm1(aOwner);

    FaOwner.Left := 500;
  End;//Constructor
end.

Und hier, warum es kompiliert. Erste Einheit B erklärt die Verwendung von Unit1 im Implementationsabschnitt. Auflösen unmittelbar die kreisförmige Referenzeinheit zwischen Unit1 et Einheit B.

Aber Delphi zu kompilieren ermöglichen, muss ich ihm etwas zu kauen auf die Erklärung von FaOwner geben: TForm1. So füge ich Stub-Klasse Name TForm1, die die Deklaration von TForm1 in Unit1 entsprechen. Als nächstes, wenn die Zeit gekommen, um den Konstruktor aufzurufen, ist TForm1 Lage passieren selbst den Parameter hat. Im Konstruktor Code, muss ich den AOwner Parameter Unit1.TForm1 typisieren. Und voilà, FaOwner seinen Satz zu Punkt auf meiner Form.

Wenn nun die Klasse TB Notwendigkeit FaOwner intern zu verwenden, ich brauche es nicht typisieren jedes Mal, zu Unit1.TForm1 weil beide Erklärung gleich. Beachten Sie, dass Sie die Deklaration zu Konstruktor

einstellen könnte

Constructor TB.create(aOwner: TForm1); aber wenn TForm1 den Konstruktor aufrufen und übergeben sich einen Parameter hat, müssen Sie es typisieren hat b.TForm1. Andernfalls wird Delphi einen Fehler telling werfen, dass beide TForm1 nicht kompatibel sind. Also jedes Mal, wenn Sie die TB.constructor aufrufen müssen Sie die entsprechende TForm1 typisieren. Die erste Lösung, einen gemeinsamen Vorfahren mit seinem besser. Schreiben Sie die Typumwandlung einmal und vergessen Sie es.

Nachdem ich es geschrieben, wurde mir klar, dass ich einen Fehler Sage gemacht, dass beiden TForm1 identisch waren. Sie sind nicht Unit1.TForm1 Komponenten und Methoden, die zu B.TForm1 unbekannt sind. Ist seit langem TB braucht sie nicht verwenden oder müssen nur die Gemeinsamkeit von TForm du bist in Ordnung gegeben verwenden. Wenn Sie etwas Besonderes zu UNit1.TForm1 von TB anrufen müssen, müssen Sie es Unit1.TForm1 typisieren.

Ich versuche es und testen Sie es mit Delphi 2010 und es kompiliert und arbeitete.

Hope es wird helfen, und Ersatz Sie einige Kopfschmerzen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top