AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Zirkuläre Referenzen

Ein Thema von tumo · begonnen am 28. Aug 2018 · letzter Beitrag vom 1. Sep 2018
Antwort Antwort
Seite 1 von 2  1 2      
tumo

Registriert seit: 28. Apr 2014
46 Beiträge
 
Delphi 10.3 Rio
 
#1

Zirkuläre Referenzen

  Alt 28. Aug 2018, 18:36
Hallo, vorab: ja, ich habe schon Google und die Hauseigene Suche benutzt, bin aber nicht fündig geworden.

Ich weiß, was Zirkuläre Unit Referenzen sind, auch, dass ich reichlich viel falsch gemacht habe, wenn diese von Nöten sind, nur steh ich gerade komplett auf dem Schlauch, wie ich diese umgehen kann bzw. so umstrukturiere, dass sie nicht mehr da sind.

Folgendes: Ich habe eine Map.pas. Wie der Name schon sagt, liegt darin die Klasse TMap, die einen 2D Array of TBlock (deklariert in Blocks.pas) speichert. Daneben vegetiert noch eine Entity.pas mit dem Typ TPlayer, welcher auf die Map.pas zwecks Kollisionserkennung zugreift.
Nun möchte ich einen neuen Blocktyp einführen: Blöcke mit denen man interagieren kann. Damit der Player dies tun kann, dachte ich an eine neue Block Klass TActionBlock, welche die procedure OnAction (oder so) besitzt. Als Parameter wäre da ja ein TPlayer angemessen, damit ich weiß, welcher Player denn nun agieren möchte. Gleichzeitig dachte ich, es wäre klug, dem Player immer den gerade nutzbaren Block zu speichern (logischerweiße vom Typ TActionBlock). Da es hier sehr deutlich zu einem Kreis kommt (TPlayer <--> TActionBlock), habe ich nur die Position des Blocks gespeichert, geht ja auch.
Nur gibt es noch immer eine Referenzschleife, die ich nicht zu umgehen weiß.

TPlayer -> TMap -> TActionBlock -> TPlayer.

(Sollten Code Schnipsel erwünscht sein, würde ich diese bereitstellen)

Vielen Dank im Vorraus.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#2

AW: Zirkuläre Referenzen

  Alt 28. Aug 2018, 19:40
(Sollten Code Schnipsel erwünscht sein, würde ich diese bereitstellen)
Die (abgespeckten) Klassendeklarationen wären schon hilfreich. Dann weiß man wenigstens wovon man redet.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

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

AW: Zirkuläre Referenzen

  Alt 28. Aug 2018, 19:51
Mangels Quelltext möchte ich nur einmal ein Beispiel geben wie man so etwas behandeln kann.

Nehmen wir an du hast einen TPlayer, der Zugriff auf die TMap bekommt, damit er die benachbarten Blöcke kennt. Warum muss er die kennen? Um damit zu interagieren. Nun könnte man aber eine zusätzliche Klasse TPlayerActor schaffen, die dies übernimmt. Diese bekommt von einer übergeordneten Instanz (dem Spielfeld z.B.) gesagt, dass Player XY mit Block XY interagieren möchte. Der TPlayer könnte dies z.B. per Event dem Spielfeld mitteilen.

Auf die Weise kennt das Spielfeld die Blöcke und die Player, die Player und Blöcke sich aber nicht gegenseitig.

Wie gesagt, das ist nur ein Beispiel, gefallen würde mir die Struktur auch nicht. Aber es könnte so ähnlich sein wie bei dir und dir einen Denkanstoß geben hoffe ich.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Zirkuläre Referenzen

  Alt 28. Aug 2018, 20:41
Hallo,
TActionBlock darf nichts von TPlayer wissen, eher umgekehrt.

Ich weiß jetzt nicht, ob das mit dem Visitor-, oder Observer-Pattern lösbar ist.

Lösbar ist es auch jeden Fall durch Nutzung von Interfaces, dann bleibt die "zugrunde liegende" Klasse außen vor.
Heiko
  Mit Zitat antworten Zitat
tumo

Registriert seit: 28. Apr 2014
46 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Zirkuläre Referenzen

  Alt 29. Aug 2018, 21:16
Hallo und danke für die schnellen und vielen Antworten.

@Uwe Raabe
Delphi-Quellcode:
--------Entity.pas--------
uses Map, ...;

type
TPlayer = class(TEntity)
  private
    procedure updateCollision(AMap: TMap; newX,newY: Single); override;
  public
    NearestBlock: TBlockVector;
    constructor Create(EntityPosition: TVector; SizeH,SizeV: Single); override;
    [...]
  end;

--------Map.pas--------
uses Blocks, ...;

type
TBlocks = array of array of TBlock;

  TMap = class(TObject)
  private
    Structure: TBlocks;
  [...]
  public
  [...]
  property Grid[X,Y: Word]: TBlock read GetStructure; default;
  property Grid[APos: TBlockVector]: TBlock read GetStructure; default;
end;

--------Blocks.pas--------
uses ...;

type
TBlock = class(TObject)
[...]
end;

TActionBlock = class(TBlock)
public
procedure OnAction(APlayer: TPlayer);
end;
Ist das in etwa, was Du wolltest? Mehr? Weniger?

@jaenicke Grundsätzlich danke. Das Dilemma über Events zu lösen ist durchaus eine Variante. Ich muss zugeben mit Events zu programmieren ist mir neu (klar, Komponentenevents, ich meine hier sebstverständlich eigene). Was ich sagen will: Gibt es da eine Art Tutorialempfehlung des Chefs?

@hoika Der Idee bin ich auch sehr aufgeschlossen. Darf ich erfahren, was Visitor-/Observer-Patterns sind?
Ich habe bis dato noch nie von Interfaces gehört (außer im Unit Aufbau). Eine erst Recherche ergab nur die Tatsache, dass diese existieren und Dinge können. Auch hier die eFrage: Gibt es da etwas, was Du empfehlen kannst?

Vielen Dank im vorraus
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#6

AW: Zirkuläre Referenzen

  Alt 29. Aug 2018, 22:29
Entity.pas braucht Map.TMap .
Map.pas braucht Block.TBlock .
Block.pas braucht Entity.TPlayer .

Was dann den Kreis schließt.

Hier in diesem Falle würde ich alles in eine Unit packen, dann gibt es auch kein Problem mit der Kreis.

Geändert von Schokohase (29. Aug 2018 um 22:31 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#7

AW: Zirkuläre Referenzen

  Alt 29. Aug 2018, 23:26
Hier ein möglicher Lösungsvorschlag zum Aufbrechen des Kreises, ganz objektorientiert und ohne Verwendung von Interfaces (was sicher auch eine valide Lösung wäre). Statt direkt auf eine TPlayer-Instanz zuzugreifen, wird hier eine abstrakte Player-Klasse eingeführt.
Delphi-Quellcode:
unit Blocks;

interface

type
  TBlock = class(TObject)
  end;

  TAbstractPlayer = class abstract
  public
    procedure DoWithBlock(ABlock: TBlock); virtual; abstract;
  end;

  TActionBlock = class(TBlock)
  public
    procedure OnAction(APlayer: TAbstractPlayer);
  end;

implementation

procedure TActionBlock.OnAction(APlayer: TAbstractPlayer);
begin
  APlayer.DoWithBlock(Self);
end;

end.
Die Maps-Unit ist hier nicht relevant, da sie nur indirekt an dem Kreis beteiligt war und nicht selber einen gebildet hat.

Eigentlich würde man TPlayer direkt von TAbstractPlayer ableiten. Da aber TPlayer schon von TEntity abgeleitet wird, schalten wir eine neue Adapter-Klasse dazwischen.
Delphi-Quellcode:
unit Entity;

interface

uses
  Map, Blocks;

type
  TEntity = class
  end;

type
  TPlayer = class(TEntity)
  private
    FPlayerAdapter: TAbstractPlayer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure DoWithBlock(ABlock: TBlock);
  end;

implementation

type
  TPlayerAdapter = class(TAbstractPlayer)
  private
    FPlayer: TPlayer;
  public
    constructor Create(APlayer: TPlayer);
    procedure DoWithBlock(ABlock: TBlock); override;
  end;

constructor TPlayerAdapter.Create(APlayer: TPlayer);
begin
  inherited Create;
  FPlayer := APlayer;
end;

procedure TPlayerAdapter.DoWithBlock(ABlock: TBlock);
begin
  FPlayer.DoWithBlock(ABlock);
end;

constructor TPlayer.Create;
begin
  inherited Create;
  FPlayerAdapter := TPlayerAdapter.Create(Self);
end;

destructor TPlayer.Destroy;
begin
  FPlayerAdapter.Free;
  inherited Destroy;
end;

procedure TPlayer.DoWithBlock(ABlock: TBlock);
begin
end;

end.
Natürlich muss das noch an die tatsächlichen Gegebenheiten angepasst werden, aber das Prinzip sollte erkennbar sein.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#8

AW: Zirkuläre Referenzen

  Alt 30. Aug 2018, 08:57
Wenn ich mich nicht verlesen habe, verursacht tActionblock den Ärger. Also dessen Definition in den Player verschieben und es sollte funktionieren.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
tumo

Registriert seit: 28. Apr 2014
46 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Zirkuläre Referenzen

  Alt 30. Aug 2018, 19:02
Hallo

@Uwe Raabe Vielen vielen Dank für die Lösung Als ich die gelesen habe, habe ich erst gedacht: Ne, ist nicht ganz wie ich es brauche, aber nach einigen Minuten hat sich die Erkenntnis eingestellt: Doch, genau so könnte es klappen (Bin derzeit viel beschäftigt mit Schule, deswegen nur könnte). Ein, zwei Fragen hab ich dann doch noch.
1. Was macht class abstract mit der Klasse?
2. Warum die Adapter-Klasse? Kann ich nicht theoretisch einfach class(TEntity, TAbstractPlayer) machen?
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#10

AW: Zirkuläre Referenzen

  Alt 30. Aug 2018, 19:57
1. Was macht class abstract mit der Klasse?
Ist eigentlich nur ein Hinweis für den Entwickler. Aktuell hat das noch keine konkreten Auswirkungen. Das Vorhandensein einer abstrakten Methode genügt bereits, daß eine Klasse abstrakt ist.


2. Warum die Adapter-Klasse? Kann ich nicht theoretisch einfach class(TEntity, TAbstractPlayer) machen?
Weil Klassen in Delphi nur einen Vorfahren haben dürfen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 03:44 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