我已经思考这个面向对象的设计问题有一段时间了,但无法想出一个令人满意的解决方案,所以我想我应该把它向这里的人群开放,征求一些意见。

我有一个 游戏 代表回合制棋盘游戏的类,出于本问题的目的,我们可以假设它与大富翁类似。在我的设计中我有一个 玩家 包含方法的类 轮流.

游戏 循环遍历所有 玩家s 并调用 TakeTurn 方法来执行完成转弯所需的所有操作。我希望能够有 n 个玩家,并且能够将任意数量的玩家设置为计算机玩家。所以,我的想法是有一个 HumanPlayer 类和一个 电脑播放器 类,两者都派生自 Player。

游戏 只知道 玩家 类并简单地调用 轮流 方法对每个 玩家 反过来。我的问题在于 电脑播放器 对象可以完全自动化,即与大富翁的例子保持一致,可以使用某种逻辑决定购买房产。现在,随着 人类玩家 例如,它需要从实际用户那里获取输入才能购买房产,这似乎意味着不同的界面,并且可能意味着它们不应该派生

在没有解决问题的情况下,我无法想出一个好的解决方案 游戏 类知道各种的实际实现 玩家 明确类。我总是可以做出假设 游戏 类中永远只有人类和计算机玩家,并有效地关闭它以进行扩展,但这似乎不是很好的面向对象编程。

对此有任何意见将不胜感激。

有帮助吗?

解决方案

我认为你不应该让 Game 类处理 IO。这样,(阻塞)TakeTurn 方法将从游戏板上隐藏执行方式。它可以使用其他对象与用户进行通信。

所有 Game 类应该关心的是棋盘的状态和回合。玩家应该全部实现一个玩家接口,并隐藏游戏中的所有实现。

其他提示

如果游戏正在管理游戏状态 进行 I/O 时,游戏做得太多了。

您希望游戏紧密关注规则、回合和状态变化。游戏不知道玩家是什么;它只知道它有玩家。

您希望玩家检查游戏状态并在轮到他们时执行法律行动。

人类玩家和整个游戏 两个都 共享一个通用的 I/O 包,用于显示游戏状态并提示人们输入。

你可以充分利用Java Observable 通过使 I/O 包成为 Observer 游戏的。这样,游戏状态变化就会报告给 I/O 以进行显示或记录或两者兼而有之。

我可能不会有两个 HumanPlayerComputerPlayer 类,但是单个 Player 类在创建时使用正确的输入策略进行配置。

玩家获取信息以决定下一回合游戏的行动的方式是 仅有的 事物有所不同(至少与原始问题描述不同),因此只需将其封装在单独的抽象中即可。

无论设置游戏的高级类是什么,都应该创建两组玩家(一组是人类,另一组是计算机模拟的),并为每组玩家提供适当的输入策略,然后简单地将这些玩家对象赋予游戏对象。然后 Game 类只会调用 TakeTurn 对于每个新回合,给定玩家列表上的方法。

与其告诉游戏类只有一个人,为什么不让它在游戏的菜单/初始化期间获得该输入呢?如果有更多玩家,可以在游戏类初始化之前通过某种形式的输入(在菜单中选择玩家)来决定。

该界面 玩家 赠送给 游戏 与派生的行为正交 玩家 类。

事实是,实施 轮流 根据具体类型而变化 玩家 对象不应引起关注。

我觉得 Game 类不应该关心 Player 类的任何实现,并且也忽略用户界面。

任何用户输入都需要由 HumanPlayer 班级。

我想说的是, 游戏 类不应该关心这是计算机玩家还是人类玩家。它应该总是调用 轮流 在下一个玩家类别中。如果这是人类玩家,则由 玩家 类,与用户沟通并询问用户该怎么做。这意味着它将阻塞,直到用户做出决定。由于 UI 交互通常发生在应用程序的主线程中,因此阻塞是唯一重要的 轮流 不会阻塞整个应用程序,否则无法处理用户输入 游戏 等待 轮流.

而不是 游戏 类调用 轮流 玩家应该呼叫的所有玩家 轮流游戏 类和 游戏 类应该验证是否轮到正确的玩家。

这应该有助于解决 用户电脑 玩家问题。

我不确定这是否是你想要的

public abstract class Player 
{
  int position;
  DecisionMaker decisionDependency;

  ...

  public void TakeTurn()
  {
    position += RollDice();
    GameOption option GetOptions(position);
    MakeDescion(option);
  }

  protected int RollDice()
  {
    //do something to get the movement
  }

  protected abstract void MakeDecision(GameOption option);

}

Public class ComputerPlayer : Player
{
  public ComputerPlayer()
  {
    decisionDependency = new AIDecisionMaker();
  }

  protected override void void MakeDecision(GameOption option)
  {
    decisionDependency.MakeDecision(option);
    //do stuff, probably delgate toan AI based dependency
  }
}

Public class HumanPlayer : Player
{
  public HumanPlayer()
  {
    decisionDependency = new UIDecisionMaker();
  }

  protected override void void MakeDecision(GameOption option)
  {
    decisionDependency.MakeDecision(option);
    //do stuff, probably interacting with the a UI or delgate to a dependency
  }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top