AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Class Helper als Lösung für zirkuläre Unit-Referenzen
Thema durchsuchen
Ansicht
Themen-Optionen

Class Helper als Lösung für zirkuläre Unit-Referenzen

Offene Frage von "jaenicke"
Ein Thema von Der schöne Günther · begonnen am 25. Aug 2013 · letzter Beitrag vom 27. Aug 2013
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    
Der schöne Günther

Registriert seit: 6. Mär 2013
6.176 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 25. Aug 2013, 20:35
Delphi-Version: XE2
Diesiges Wetter. Zeit, wieder über zirkuläre Unit-Referenzen zu plauschen

Vielleicht bin ich noch zu neu in Delphi, aber ich finde das Thema ist nicht gegessen. Ich habe aktuell auch (glücklicherweise nur ein oder zwei) Fälle, in denen sich zwei Klassen gegenseitig kennen müssen. Alles direkt mit "Das ist schon Zeuge genug für schlechtes Design, mach es irgendwie anders" abzuwürgen ist mir zu billig.

Hier nun eine interessante Methode, zirkuläre Referenzen mit Class Helpern noch einmal neu anzugehen: Solving circular unit references with class helpers. Ich habe hier im Forum noch keine heißblütig geführten Diskussionen dazu gefunden. Deshalb nun dieses Thema.

Zusammenfassung: Altbewährtesbekanntes Halten einer (protected) Referenz vom Typ TObject , Casten auf den richtigen Typ mittels Helferklassen-Methode (oder Property).

Was haltet ihr davon? Das einzige was mich stört: Man könnte vergessen, die Helfer-Unit einzubinden und sich anschließlich wundern, wo denn der Verweis (bsp. des Hundes auf seinen Halter) steckt.

Hier einmal noch die Kurzfassung:

Delphi-Quellcode:
// Hundebesitzer.pas
uses
   Hund
;

type THundebesitzer = class
   public var
      name: String;
      hund: THund;
end;
Delphi-Quellcode:
// Hund.pas
type
   THund = class
      protected var // An 'private' kommt auch ein Helper nicht mehr ran
         besitzer_uncasted: TObject;
      public var
         name: String;
   end;
Delphi-Quellcode:
// HundHelper.pas
uses
    Hund,
   Hundbesitzer
;

type
   THundHelper = class helper for THund
      private
         function GetBesitzer: THundebesitzer;
         procedure SetBesitzer(const Value: THundebesitzer);
      public
         property besitzer: THundebesitzer read Getbesitzer write Setbesitzer;
   end;

implementation
   function THundHelper.Getbesitzer: THundebesitzer;
   begin
     if besitzer_uncasted is THundebesitzer then
      Result := besitzer_uncasted as THundebesitzer
     else
      Result := nil //Oder Exception?
     ;
   end;

Geändert von Der schöne Günther (25. Aug 2013 um 20:39 Uhr) Grund: Kurzbeispiel hinzugefügt
  Mit Zitat antworten Zitat
silver-moon-2000

Registriert seit: 18. Feb 2007
Ort: Schweinfurt
170 Beiträge
 
Delphi XE Professional
 
#2

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 01:10
Hier nun eine interessante Methode, zirkuläre Referenzen mit Class Helpern noch einmal neu anzugehen
Wenn ich das Thema ClassHelper richtig verstanden habe, habe ich doch durch die ClassHelper eine THund-"PseudoKlasse" in der folgenden Form
Delphi-Quellcode:
type
   THund = class
      private
         function GetBesitzer: THundebesitzer; //aus ClassHelper
         procedure SetBesitzer(const Value: THundebesitzer);//aus ClassHelper
      protected
         besitzer_uncasted: TObject;
      public
         name: String;
         property besitzer: THundebesitzer read Getbesitzer write Setbesitzer;//aus ClassHelper
   end;
Ich kann also innerhalb von THund auf den Besitzer entweder über das property direkt zugreifen oder über das ungecastete Objekt, wobei ich dann jedes Mal casten muss?

Was mich dabei stören würde, wäre die Tatsache, dass ich im Setter / Getter des properties keine zusätzliche Logik unterbringen darf (von dem Cast einmal abgesehen), wenn ich nicht will, dass diese zusätzliche Logik bei jeder Verwendung des properties ausgelöst wird.
In dem Beispiel vielleicht jetzt schwerer einsichtig, aber manchmal muss/möchte man zwischen einem Zugriff von innerhalb und außerhalb der Klasse unterscheiden (z.B. wenn man zusätzlich Aktionen durchführen möchte, wenn "von außen" (wozu properties imho gedacht sind) auf das Objekt zugegriffen wird).

Delphi-Quellcode:
procedure THundeHelper.SetBesitzer(const Value: THundebesitzer)
begin
  if Assigned(value) then
  begin
    besitzer_uncasted := value;
    if value.name = "Der schöne Günther" then
      //schlabbereNeuenBesitzerAb
    else
      //knurreNeuenBesitzerAn
  end;
end;
Wenn ich nun will, dass die Namensabfrage des neuen Besitzers nur stattfindet, wenn ich den Benutzer von außen setze und nicht von innerhalb der Klasse THund, dann würde der Zugriff von innerhalb nur über das ungecastete Object (das ich dann casten muss) und der Zugriff von außen über das property stattfinden müssen.

Oder bringt man in Settern/Gettern sowieso keine zusätzliche Logik unter? Ist das schlechter Programmierstil?

Ich hoffe, ich konnte meine Gedanken halbwegs klar formulieren
Tobias
Bitte nicht hauen , ich weiß es nicht besser
  Mit Zitat antworten Zitat
Benutzerbild von bernau
bernau

Registriert seit: 1. Dez 2004
Ort: Köln
1.295 Beiträge
 
Delphi 12 Athens
 
#3

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 07:00
Was haltet ihr davon? Das einzige was mich stört: Man könnte vergessen, die Helfer-Unit einzubinden und sich anschließlich wundern, wo denn der Verweis (bsp. des Hundes auf seinen Halter) steckt.
Denk bei ClassHelpern immer daran: Es kann nur einen geben.

Wenn du jetzt schon einen Classhelper für deine Klassen vergibst, kannst du keinen weiteren ClassHelper mehr für die Klasse verwenden. Classhelper sind ja eigendlich dazu gedacht, an eine Klasse etwas anzuflanschen, weil man an die Ursprungs-Unit nicht dran kommt. Du verbaust quasi anderen die Möglichkeit deine Klasse zu erweitern (ohne eine Ableitung zu schreiben).
Gerd
Kölner Delphi Usergroup: http://wiki.delphitreff.de
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#4

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 07:27
Diese Lösung mit dem Zeiger-In-Den-Nebel (TObject) ist doch -ehrlich gesagt- Quark. Innerhalb von THund kannst Du ja gar nicht auf den Hundebesitzer zugreifen. Somit ist diese Umschiffung (eine Lösung ist das ja nicht) des Henne-Ei-Problems mittels Classhelper vielleicht ein Notbehelf, aber imho ein ziemlich einengender.

Das Problem tritt ja dann auf, wenn man eine eigentlich saubere Implementierung in unterschiedliche Units aufteilt. Wären sie in einer Unit, gäbe es das Problem nicht:
Delphi-Quellcode:
Type
  THundebesitzer = class;
  THund = class
     fHundebesitzer : THundebesitzer;
  public
     Hundebesitzer : THundebesitzer read ....;
  End;
Wieso verwendest Du nicht einfach Interfaces? Wenn man das konsequent durchzieht und keine kranken Sperenzien anstellt, gibt es auch keine Probleme.

Geändert von Furtbichler (26. Aug 2013 um 07:31 Uhr)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 08:14
Und was ist mit der Möglichkeit, in einer dritten Unit ein generisches Dictionary anzulegen, was die Zuordnung von Hund und Hundehalter speichert?
Außerdem könnte so ein Hundebesitzer leicht mehrere Hunde haben oder umgekehrt ein Hund zwei Besitzer (Herr und Frau Müller).
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#6

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 08:17
Und was ist mit der Möglichkeit, in einer dritten Unit ein generisches Dictionary anzulegen, was die Zuordnung von Hund und Hundehalter speichert?
Außerdem könnte so ein Hundebesitzer leicht mehrere Hunde haben oder umgekehrt ein Hund zwei Besitzer (Herr und Frau Müller).
Hier geht es nicht um Design, sondern um die Lösung eines allgegenwärtigen Problems: Zirkuläre Referenzen. In diesem Fall *soll* es ja so sein, das ein Hund maximal einen Besitzer hat. Das ist sozusagen Constraint-By-Design. Bei deiner Lösung müsste man das in der Dictionary-Klasse explizit ausprogrammieren.

Tendentiell ist so eine Relationsklasse natürlich ein schöner Ansatz, wenn die Besitzverhältnisse mit Logik verbunden sind.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.650 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 08:46
In den meisten Fällen lässt sich das auch viel einfacher durch eine saubere Schnittstelle lösen. Denn die Frage ist doch was man von dem Objekt Hund im Objekt Besitzer machen will. Meistens kann man das auch über Events oder ähnliches lösen.
Delphi-Quellcode:
// Zum Beispiel nicht:
Hund.Bellen;
Hund.Besitzer.Schimpfen;

// sondern:
Hund.OnBellt := Besitzer.HundBelltEvent;

procedure TBesitzer.HundBelltEvent;
begin
  Schimpfen;
end;

// und dann nur:
Hund.Bellen;
// EDIT:
Interfaces lösen das Problem auch nicht, wenn man tatsächlich eine echte Referenz in beide Richtungen will. Man könnte allerdings die Referenz in einem abgeleiteten Interface unterbringen und nur das Basisinterface zurück referenzieren. Das geht bei Klassen aber auch.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (26. Aug 2013 um 08:49 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#8

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 08:48
An 'private' kommt auch ein Helper nicht mehr ran
Doch, kommt er - man muss nur Self davor schreiben.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#9

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 09:17
Ich packe Klassen, die sich gegenseitig benötigen, einfach in dieselbe Unit. So schlimm ist das gar nicht. Lange Units sind halt auch irgendwie der Pascal-Way... guckt euch doch nur mal die VCL an. Und zur Not könnte man immer noch Include-Dateien verwenden – jeweils Implementation und Interface getrennt. Damit bastelt man sich sowas ähnliches wie bei C++.
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.381 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Class Helper als Lösung für zirkuläre Unit-Referenzen

  Alt 26. Aug 2013, 09:24
// EDIT:
Interfaces lösen das Problem auch nicht, wenn man tatsächlich eine echte Referenz in beide Richtungen will. Man könnte allerdings die Referenz in einem abgeleiteten Interface unterbringen und nur das Basisinterface zurück referenzieren. Das geht bei Klassen aber auch.
natürlich lösen die Interfaces das Problem. Zumindest wenn man Interfaces wie Interfaces verwendet und nicht wie KLassen

Grüße
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz