2010-04-29 143 views
4

我有一個單獨的單元中的播放器類,如下所示:循環參考修復?

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

我也有一個世界級的獨立單元如下:

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

我已經做到了這種方式,使玩家可以通過FWorld從世界獲得數據,並且世界上的其他物體也可以以類似的方式獲取玩家數據。

正如你可以看到這個結果是一個循環引用(因此不起作用)。我已經讀過,這意味着糟糕的代碼設計,但我想不出任何其他更好的方法。什麼可能是更好的方法來做到這一點?

乾杯!

回答

6

每隔一段時間,這就是所謂的,然後你做這樣的:

//forward declaration: 
TWorld = class; 

TPlayer = class 
private 
    FWorld: TWorld; 
public 
end; 

TWorld = class 
private 
    FPlayer: TPlayer; 
public 
end; 
+0

當你沒有聲明一個指針時,這真的起作用嗎?我沒有永遠使用帕斯卡。 – 2010-04-30 00:59:26

+1

是的,那是有效的。有可能我不會使用簡單的Pascal,但在這種情況下,你不會有課程開始。 – 2010-04-30 07:22:46

+0

是的,它的工作原理。不要使用Delphi中的類指針類* * – 2010-04-30 08:24:45

0

把兩個班爲一個單元,或提取抽象基類的類之一的,但這不參考其他班級。然後你在其他類定義引用這個抽象基類:

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

如果您在t世界創造TPlayer可以執行使用子句中引用原始TPlayer單元。否則,你根本不需要參考原始的TPlayer單元。

這被稱爲dependency inversion

4

就像Ozan說:大部分的時候,一個很好的答案是創建虛擬方法的基類:

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; 
... 

,或者具有類似的效果,發佈的接口:

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; 
... 

根據代碼的工作方式,您可能希望將世界隱藏在抽象層(如上面的示例中)或Player(如Ozan所建議的)後面。

+0

+1我更喜歡抽象世界,因爲世界可能知道玩家的全部內容,但玩家並不知道關於世界的所有事情(比如關於隱藏在樹後面的怪物:-) – 2010-05-06 02:06:39