我一直在编写棋盘游戏的软件版本。到目前为止,我已经编写了与游戏板上的物理对象相对应的类。我很喜欢编写程序逻辑,但是我发现很多逻辑类都需要访问相同的对象。
起初我将相应的对象传递给方法,因为它们被调用,但这变得非常乏味,特别是当方法需要许多对象来执行它们的任务时。为了解决这个问题,我创建了一个初始化和存储我需要的所有对象的类。这允许我通过调用Assets.dice()来访问任何类中的对象。例如。
但是现在我已经考虑过了,这似乎不对。这就是为什么我在这里,我担心我创造了某种神级。这种恐惧是没有根据的,还是我为灾难创造了一个食谱?
答案 0 :(得分:7)
你基本上碰到了单身人士模式。在大多数情况下,这是一个糟糕的模式。通过允许您的应用程序的任何部分几乎可以在任何时间访问这样的全局数据,最终会出现难以维护,调试以及最重要的测试代码。
我认为最好创建一个包含当前骰子,片段等的“上下文”,并根据需要将上下文传递给需要使用它的方法/类。这是更清洁,虽然是的,它必须在任何地方传递它是一种痛苦。但是您可以获得以下优势:您可以跟踪谁在访问Context时,还可以创建模拟上下文以进行测试。如果将上下文传递给高级对象,并且必须将其传递给它的子组件,那么从开始到结束就知道上下文是什么以及它来自何处。
另外,理想情况下,使Context不可变是件好事。这可能是不可能的。但是,如果你可以创建一个捕获当前状态并且不可变的新上下文,那么如果每个给定的转向,你可以减少你的应用程序的更多惊喜。
答案 1 :(得分:2)
听起来你问的是面向对象编程的一般哲学。通常,您会发现将实际对象建模到类中总是对您的代码最有意义。
帮助我解决这个问题的一个指南是两个拟人类之间的对话(如果有人知道这个引用的原始来源,我会很感激链接!):
A组对B级说:“给我x的值。”
B类:“你为什么想要x的值?”
A类:“所以我可以把它弄好。”
B级:“问我,我会为你准备它。”
这有助于推动一个类意图封装数据和对其执行操作。一般来说,这是一个比喻,它帮助我更好地组织我的代码。
您可能想要了解的另一件事是一些常见的面向对象Design Patterns。像游戏骰子这样的东西可能更有意义Singleton,因为你不需要多个实例。
如果你想要对设计模式有一个很好的介绍,我建议你选一本优秀的Head First Design Patterns书。
答案 2 :(得分:0)
它真的是一个“上帝”类,或者仅仅是一个“上下文”,它是一个游戏的所有相关对象实例的“容器”,然后传递给不同的方法调用(这样你只有一个参数)?后者很常见,我认为没有错,但在这种情况下,容器本身没有真正的功能。
答案 3 :(得分:0)
感谢您提出这个问题。我一直想知道同一个问题。跨方法传递对象并保持参数有限需要创建可以容纳所有这些对象的类。
我仍然认为设计并不坏,因为你需要一个跨越多个层的Domain类。如果这个Domain类没有携带必要的对象而没有执行任何逻辑,那么应该没问题。
答案 4 :(得分:0)
拥有那种可以访问所有内容的上下文类与拥有全局变量非常相似。同样的缺点也适用。可以通过任何方法读取和更改全局变量。这将使用全局变量的所有内容相互耦合。耦合是不好的,因为当事物耦合时,一个对象的改变可能导致另一个对象中的某些东西。当耦合程度增加时,管理复杂性变得非常困难(蝴蝶在我们的玩家类中拍打它的翅膀会导致你的骰子类异常)。变化和额外的发展变得更加困难。难以察觉和隐藏的错误变得不可避免。
因此,例如,有一天在测试您的应用程序时,您可能会注意到您的骰子对象表现得很奇怪。你调用dice.roll()并看到它有时会返回1。但在这种情况下,这是不可能的,因为你的玩家正在滚动其中两个。你调试并以某种方式注意到numberOfDice属性在某些时候变为1。使用像你这样的上下文方法,找到谁将numberOfDice更改为1并不容易,因为每个人都可以通过上下文对象访问骰子。你明白了吗?
那么解决方案是什么?我喜欢OO编程的一个比喻是分而治之。您需要找到可以相互隔离的行为,流程和对象。您需要将问题划分为可管理的部分,这些部分可以与应用程序中正在进行的其他工作隔离开来。
学习如何做到这一点当然不容易,需要大量的学习,阅读,思考,讨论和编码。