在C ++中删除类之间的循环依赖关系

时间:2018-11-28 09:13:20

标签: c++ class oop circular-dependency

假设我们正在制作一个两人纸牌游戏,并且我们有称为Game,Player和Card的类。游戏包含指向两个玩家的指针,并为玩家提供界面。牌手包括牌手的生命值,其魔力以及其矢量牌。卡是一个抽象类。每张卡都需要花费魔法才能使用。

问题在于,每张纸牌在被使用时都可以通过多种方式改变游戏状态。例如,我们可以有一张牌,使牌手的生命值加倍,一张牌使敌方玩家中毒两回合,一张牌会破坏棋盘上的所有小兵,一张牌会为棋盘上已经存在的每个小兵创建副本,等等。可能性真的是无止境的。我能看到的唯一解决方案是在每张纸牌中都有一个指向游戏的指针,但这似乎不太优雅。

还有其他解决方案吗?

2 个答案:

答案 0 :(得分:6)

您的基本想法是正确的,但是您应该进一步增强它,以保持较高的抽象和封装水平。

因此,在您的示例中,假设您有一个Card类,它是现有类的实例。

第一件事是将卡的效果与卡本身分开,例如:

class CardEffect {
 // TODO ...
};

class Card {
private:
  const CardEffect* effect;
};

因此,现在卡本身不需要了解游戏。但是,让我们更深入地了解这一点:CardEffect不需要知道Game类的每个细节,它需要做的就是将效果应用到游戏中。这可以通过为效果提供一个单独的接口来完成,该接口仅公开应用该效果所需的内容,因此类似这样。

class GameInterface {
public:
  virtual const std::vector<Player*>& getPlayers() = 0;

  virtual damagePlayer(Player* player, int amount) = 0;
  virtual applyPeriodicDamage(Player* player, int turns, int amount) = 0

  ..
};

class CardEffect {
  virtual applyEffect(GameInterface* interface) = 0;
};

class Card {
private:
  const CardEffect* effect;
};

现在这只是一个示例,由于每种特定情况都不相同且有不同的要求,因此没有针对您的问题的最终解决方案,这只是为您提供了一个基本思路,使您可以尝试在保持代码优雅的同时将其封装起来描述性强,易于管理。

答案 1 :(得分:2)

只要您有交叉依赖项,例如:

class Card
{
   Game* game;
   void f() {
     game->method1();
   }
}; 

class Game
{
   std::vector<Card> cards;
 public:
   void method1();
};

其中一个依赖项应实现如下接口:

class IGame
{
 public:
   virtual void method1()=0;
};

class Card
{
  IGame* game;
  void f() {
     game->method1();
   }
}; 

class Game : public IGame
{
   std::vector<Card> cards;
 public:
   virtual void method1();
};

而且您再也看不到交叉依赖性。