4

次のように、別のユニットにPlayerクラスがあります。

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

私はまた、次のように別のユニットにワールドクラスを持っています:

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

プレーヤーがFWorldを介してワールドからデータを取得できるように、またワールド内の他のオブジェクトが同様の方法でプレーヤーデータを取得できるように、このようにしました。

ご覧のとおり、これは循環参照になります(したがって機能しません)。これは悪いコード設計を意味することを読みましたが、他の方法を考えることはできません。それを行うためのより良い方法は何でしょうか?

乾杯!

4

3 に答える 3

6

時々これが要求され、それからあなたはこのようにそれをします:

//forward declaration:
TWorld = class;

TPlayer = class
private 
  FWorld: TWorld;
public
end;

TWorld = class
private
  FPlayer: TPlayer;
public
end;
于 2010-04-30T00:47:13.947 に答える
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;
...

コードの動作に応じて、抽象レイヤー(上記の例のように)またはプレーヤー(Ozanによって提案されたように)の背後にワールドを非表示にすることができます。

于 2010-04-30T07:12:03.240 に答える
0

両方のクラスを1つのユニットに入れるか、一方のクラスの抽象基本クラスを抽出します。これは、もう一方のクラスを参照しません。次に、他のクラス定義でこの抽象基本クラスを参照します。

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

TWorldでTPlayerを作成する場合は、実装のuse句で元のTPlayerユニットを参照できます。それ以外の場合は、元のTPlayerユニットをまったく参照する必要はありません。

これは依存性逆転と呼ばれます。

于 2010-04-30T02:28:07.047 に答える