单例使用的好例子

Good example of Singleton usage

最近我阅读了很多关于 Singleton 模式的内容。就我而言,只有在没有多个对象的意义时,以及需要从整个程序访问它们时,才应使用单例对象。我的问题很简单,仅用于教育目的。 在制作 棋盘游戏 模拟器时,例如 MonopolyCatan 是否正确创建骰子(可抛棋盘游戏骰子)作为单身 class?

这里要问的问题是你从单例行为中得到了什么价值。您将此描述为“仅当没有超过一个的意义,并且需要从整个程序访问它们时”。细微差别是 即使拥有多个实例没有用,您也可以选择反对 Singleton:如果不这样做,允许创建多个实例可能没问题'没有任何明显的缺点。

请记住,如果您很好地实现了 Singleton,则该对象在应用程序的整个生命周期内都不会被销毁,并且您需要同步对象的创建,这样多个线程就无法创建多个实例。对于重对象或具有重依赖性的对象,这实际上可能会导致更大的长期内存使用,因为您无法在应用程序的整个生命周期中销毁或垃圾​​收集该对象。这在哪些对象 可以 是单例和哪些对象 应该 是单例之间留下了差距。这需要你的判断。

需要考虑的一些因素:

  1. 如果创建多个应用程序,您的应用程序是否正确?对于 DatabaseService 或 StorageService 之类的东西,答案可能是“否”,在这种情况下,绝对需要单例行为。

  2. 如果创建多个应用程序,您的应用程序是否会有良好的性能?对于像 WebRequestService 这样的东西,拥有一个对象队列或管理请求可能会有一些额外的价值,这可能是使它成为单例的一个很好的动机。

  3. 如果您的对象 没有 是 Singleton,创建它的成本是否很高,或者创建它的次数是否足够频繁以至于想要重用该对象?在这种情况下,您必须权衡创建开销与单例开销。想象一个词典或拼写检查器,即使您创建一个新的词典或拼写检查器,其结果也是正确的,但您希望最大限度地减少从磁盘读取词典文件的次数。有时有比 Singleton 更多的选择,,这会以更少的成本为您提供一些好处。

你的骰子 class:

  • 如果一个 Dice class 恰好代表创建对象时确定的一次掷骰,显然它不能是 Singleton,因为那样你只能掷一次骰子并且它总是 return 相同的值。 You probably don't want that.
  • 如果你的 Dice class 代表一个纯(伪)随机数生成器,它通常不必是单例:创建它可能很便宜,并且在顺序。您可以合理地使其“可重用”或将 Dice 对象保存在池中以避免重新创建它们,但如果我正在编写代码,我认为这样做不太值得。
  • 如果您希望您的游戏是可重复的,例如在集成测试中有可预测的游戏,那么让 Dice 对象成为 Singleton 可能是有意义的:在这种情况下,您可能需要单个对象,这样它就可以以相同的顺序调用并接收相同的随机种子结果。
  • 如果您要调用 https://www.random.org 之类的随机数服务,则创建对象 Singleton 可能很重要,这样它就可以批处理、缓存和重用这些请求。

对于“Dice”,我会使其“无作用域”,每次都创建一个新实例并允许在测试中替换它。相比之下,您的 Board、Game 或 GameState 对象在整个应用程序中是 Singleton 可能是有意义的。