Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular reference fix?

Tags:

delphi

pascal

I have a Player class in a separate unit as follows:

TPlayer = class
private
  ...
  FWorld: TWorld;
  ...
public
  ...
end;

I also have a World class in a separate unit as follows:

TWorld = class
private
  ...
  FPlayer: TPlayer;
  ...
public
  ...
end;

I have done it this way so that the Player can get data from the world via FWorld, and so that the other objects in the world can get the player data in a similar manner.

As you can see this results in a circular reference (and therefore does not work). I have read that this implies bad code design, but I just can't think of any better other way. What could be a better way to do it?

Cheers!

like image 365
sirxemic Avatar asked Dec 29 '22 18:12

sirxemic


2 Answers

Every once in a while this is called for, and then you do it like this:

//forward declaration:
TWorld = class;

TPlayer = class
private 
  FWorld: TWorld;
public
end;

TWorld = class
private
  FPlayer: TPlayer;
public
end;
like image 91
500 - Internal Server Error Avatar answered Dec 31 '22 14:12

500 - Internal Server Error


Just like Ozan said : most of the time, a good answer is to create a base class with virtual methods :

unit BaseWorld;
TBaseWorld = class
  function GetWorldInfo() : TWorldInfo; virtual; {abstract;}
...

unit Player;
TPlayer = class
  FWorld : TBaseWorld;
  constructor Create( AWorld : TBaseWorld );
...

unit RealWorld;
TWorld = class(TBaseWorld)
  function GetWorldInfo() : TWorldInfo; override;
  ...

TWorld.AddPlayer();
begin
  TPlayer.Create(Self);
end;
...

or, with a similar effect, publish an interface :

unit WorldIntf;
IWorldInterface = interface
  function GetWorldInfo() : TWorldInfo;
...

unit Player;
TPlayer = class
  FWorld : IWorldInterface;
  constructor Create( AWorld : IWorldInterface );
...

unit RealWorld;
TWorld = class(TInterfacedObject, IWorldInterface)
  function GetWorldInfo() : TWorldInfo;
  ...

TWorld.AddPlayer();
begin
  TPlayer.Create(Self);
end;
...

Depending on how your code works, you may want to hide the World behind an abstract layer (as in the above examples) or the Player (as suggested by Ozan).

like image 22
LeGEC Avatar answered Dec 31 '22 13:12

LeGEC