当函数依赖于两个不同的类时,避免类型检查

时间:2015-06-30 05:50:26

标签: c++ oop design-patterns

我试图编写各种游戏中心,这些游戏中心基本上是可以在命令行轻松播放的棋盘游戏或游戏的集合。 (Tic Tac Toe,Connect Four等)用户还可以选择制作两台播放器中的任何一台。如果我只制作Tic Tac Toe,这不会成为一个问题,因为我可以'#34;移动"在Player的人类和计算机子类中实现,然后以多态方式调用正确的,但是通过添加其他游戏,我不确定如何摆脱类型检查。例如,如果move是播放器中的一个函数,那么除了通过类型检查之外,该函数还能知道是否根据Tic Tac Toe或Connect Four的规则移动?

我想要为每个场景设置一个具有不同子类的单独移动类,但我不确定这是否正确或如何实现它。

顺便说一句,这是用C ++编写的。

2 个答案:

答案 0 :(得分:0)

这个怎么样:

enum GameType {
TicTacToe,
ConnectFour,
SnakesLadders,
Battleships,
};

然后将GameType gt存储在您正在使用的游戏对象中。然后在每个方法中执行switch(gt)

答案 1 :(得分:0)

如果您希望所有游戏都从相同的game_base基类继承,那么您需要使用这些游戏的人不会知道"知道"他们正在玩哪种游戏。

我的意思是什么?你问过

  

例如,如果move是播放器中的一个函数,那么除了通过类型检查之外,该函数将知道是否根据Tic Tac Toe或Connect Four的规则移动?

让我问你这个问题 - 说你确实像你描述的那样解决了这个问题。现在你要添加一个新游戏(比如,跳棋)。您是否需要更改player以了解如何玩跳棋?

如果是这样 - 那么你的游戏就不应该使用继承(不应该继承game_base

为什么呢?因为基本上你是在说#34;我的player课程必须内置所有游戏的所有可能性"。如果是这样的话,为什么要有不同的游戏类?

作为一种解决方案,我会这样说:

  • 如果需要根据井字游戏或连接四人移动,人类玩家类怎么样? GAME类应该告诉它!不仅如此 - 假设玩家根本不了解游戏!告诉玩家当前的法律行动是什么!

一个例子:

class game_base{
  // returns the number of players in this game. 
  // Doesn't change during play
  virtual int num_players() = 0;
  // returns the current player - the player whose turn it is now
  virtual int curr_player() = 0;
  // returns a string that describes (or draws) the current
  // game state
  virtual std::string draw_board()const = 0;
  // returns all the possible legal moves the player can 
  // make this turn
  virtual std::vector<std::string> curr_turn_possible_moves()const = 0;
  // Plays the given move. Has to be one of the moves
  // returned by curr_turn_possible_moves()
  virtual void play(std::string move) = 0;
  // returns the player who won the game, or -1 if the 
  // game is still ongoing
  virtual int won() = 0;
};

了解如何以相同player课程可以播放您所有游戏的方式使用此游戏课程。

你甚至可以制作一个&#34;检查所有选项,最多可达N级&#34;适用于每场比赛的电脑播放器!

  • 关于电脑播放器:你可以制作一个&#34;泛型&#34;尝试前进N步以寻找获胜策略的计算机播放器(您需要将选项添加到virtual game_base *copy()const当前游戏状态)。但实际上你需要为每个游戏量身定制一个电脑播放器(只播放那个游戏)。

那你怎么做的?更重要的是 - 你怎么知道为每个游戏选择哪个电脑玩家?

所有计算机玩家都将从computer_player_base类继承(可能只有一个函数play在给定游戏时播放下一步)。诀窍是 - 如果您现在想要为游戏添加新的计算机播放器(无论是新游戏还是现有游戏的其他可能的计算机播放器),您需要一种方法来注册&#34;那个球员。你想要的东西看起来像:

std::vector<computer_player_base*> possible_computer_players(const game_base*game);

返回知道如何玩给定游戏的所有可能的计算机玩家。最简单的方法是让计算机播放器类本身告诉你它是否可以播放给定的游戏。所以它看起来像这样:

class computer_player_base{
  // return true if this class knows how to play this game
  // implemented using dynamic_cast - something like this:
  // return dynamic_cast<connect_4*>(game) != 0;
  virtual bool can_play(game_base *game) = 0;
  // plays the next turn of the game
  virtual void play(game_base *game) = 0;
};

然后,例如,可以选择的所有计算机播放器的全局列表

std::vector<computer_player_base*> all_computer_players

您将填写每台计算机播放器和一个功能

std::vector<computer_player_base*> possible_computer_players(game_base *game)
{
  std::vector<computer_player_base*> res;
  for (auto p:all_computer_players)
    if (p->can_play(game))
      res.push_back(p);
  return res;
}