Circular fix?

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

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

I also have the World class in a separate block as follows:

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

I made it so that the player can receive data from the world through FWorld, and so that other objects in the world can receive player data in a similar way.

As you can see, this leads to a circular reference (and therefore does not work). I read that this implies poor code design, but I just can't think of anything else. What could be the best way to do this?

Hurrah!

+4
source share
3 answers

This is called from time to time, 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; 
+6
source

Just like Ozan said: most of the time, the 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 the 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 can hide the world behind an abstract layer (as in the examples above) or Player (as suggested by Ozan).

+4
source

Put both classes in one unit or extract the abstract base class of one of the classes that does not reference the other class. Then you refer to this abstract base class in the definition of another class:

 uses UAbstractPlayer; TWorld = class ... private FPlayer: TAbstractPlayer; ... 

if you create TPlayer in TWorld, you can refer to the source TPlayer block in the proposal to use the implementation. Otherwise, you do not need to reference the original TPlayer block at all.

This is called dependency inversion .

0
source

Source: https://habr.com/ru/post/1308371/


All Articles