【问题标题】:What's the "OOP way" to access data in a contained class object, from another contained class object? [closed]从另一个包含的类对象访问包含的类对象中的数据的“OOP 方式”是什么? [关闭]
【发布时间】:2021-08-09 14:31:50
【问题描述】:

出于教育目的,我正在尝试在 C# 控制台中创建纸牌游戏“大富翁交易”的副本。我的班级设计有一个问题,我不知道如何解决。我有两个班级,Game 和 Player。 Game 控制游戏的状态,并包含Player 对象的列表。

目前它的工作方式是Game 类控制一切。 Player 基本上是一个容器类:它包含玩家收藏中的所有卡片。决策由Game 类完成,因为它可以看到所有玩家,因此知道哪些动作是可能的。

例如,如果玩家 1 想从玩家 2 那里偷一张牌,我的程序必须首先验证玩家 2 是否有任何牌可以偷。玩家 1 不知道这一点,因为它只是 Player 对象列表中的一个对象。所以Game 类有一个方法可以检查玩家可以做出的所有可能的动作,要求玩家选择他们想要做出的动作,然后为他们执行那个动作。

我的问题:我认为这不是好的 OOP 类设计。我认为我应该将决策委托给 Player 类,而不是 Game 类 - 否则我的 Game 类将变得臃肿,其中包含许多与玩家行为和决策相关的方法,而不是游戏陈述自己。但是,我不知道如何实现这一点。

可能的解决方案:

  1. 创建一个GameState 对象,其中仅包含其他玩家卡片的有限视图,并将其传递给Player 对象(似乎是最简单的方法,但我想它会创建冗余数据,这是浪费内存。)
  2. 将整个 Game 对象的引用传递给 Player 类(我可以这样做 - 这不像我要通过 ComputerPlayers 编写程序来作弊 - 但感觉也不是好的 OOP 设计)
  3. 放弃,将所有游戏逻辑(包括计算机 AI)放在 Game 类中,并接受 Player 只是一个数据容器,而不是决策者。
  4. 以不同的方式重新设计我的课程。
  5. 我还错过了什么?

这里有什么明显的解决方案吗?谢谢。


编辑:我试图减少问题中的过多细节,因为它因“焦点不足”而关闭。如果需要进一步修改,请告诉我。

【问题讨论】:

  • 这是一个很长很宽泛的问题。对于这个in the Top 5 recurrent question,你可以根据你的needs or opinion使用:单例、静态数据成员、事件、静态运行方法模式、带参数的构造函数、组合、聚合等等……
  • 方法外的类中包含的状态是Field 或Property。
  • 一般来说,我们经常尝试区分包含应用程序逻辑的类和表示数据的类。因此,如果您有一个代表玩家的 Player 类,我不会在其中嵌入任何实际逻辑,只是足以初始化玩家的属性并维护玩家的外部状态。
  • 这篇文章几分钟内产生的(长)cmets 的数量清楚地表明这是一个讨论而不是问答。 (在我看来,这似乎表明评论者也不真正知道 SO 应该如何工作;但这是一个单独的问题。)理想情况下,关于 SO 的问题应该导致一个清晰而正确的答案。不是推荐,不是最佳答案,而是正确答案。这个问题没有单一的正确答案,因此其他答案将是不正确的。这仍然是一个很好的问题;但是对于讨论论坛而不是SO。很好的问题,错误的地点。

标签: c# class oop console-application class-design


【解决方案1】:

如何创建一个代表您可以在游戏中执行的操作的操作类。然后游戏只有两个方法 Game.verifyAction(action) 和 Game.executeAction(action)。游戏包含验证和执行操作所需的所有数据。

接下来,将玩家视为数据容器,这意味着玩家不会认为它只是包含在状态中。玩家可能包含诸如分数、id 等数据。实际上认为您有一个负责选择动作的代理类。所以 Agent.think(Game) 返回代理在这个状态下想要采取的动作。

现在很容易将主循环移到 Game 类之外,您还可以使用 GUI 轻松替换 Agent,一旦人类选择了一个动作就会返回一个有效的动作。

【讨论】:

  • 谢谢,我认为这是有道理的。所以你建议一个代理类将包含一个包含玩家数据和决策方法的玩家字段,并且你基本上将“游戏”作为对象传递给代理的决策方法?
  • 是的,还请阅读我关于隐藏信息的其他评论。通过从玩家级别中移除决策,您可以让自己做更多的事情。例如通过 GUI 控制玩家而不是使用代理
  • @Lou,这是一个很好的解决方案;但它描述的范式是过程编程。由于问题被标记为OOP,您应该知道,通过分离其行为将Player 域对象降级为数据结构与OOP 完全相反。
  • 哦,谢谢你告诉我@jaco0646!
  • 有趣,我可以看到这与 OOP 原则背道而驰,但我从未见过这种解决方案。以我的经验,这种方法使设计更加灵活,但它肯定是以无法为游戏添加新玩家为代价的。我通常通过一个 GameRunner 类来解决这个问题,该类将代理列表作为输入。
猜你喜欢
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 2018-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多