4

我一遍又一遍地阅读,出于各种原因,应该避免使用单例。我想知道如何正确处理类代表唯一系统资源的情况。例如,使用 SDL 的 AudioOutput 类。由于 SDL_OpenAudio 一次只能打开一次,因此拥有多个此类对象是没有意义的,在我看来,防止意外制作多个对象实际上会很好。

只是想知道有经验的程序员对此有何看法,我是否错过了另一种选择?

4

3 回答 3

9

Singleton 的问题之一是它的使用通常破坏了控制反转原则(或SOLID方面的依赖反转)。

Singleton 不仅阻止创建多个对象,它还公开了这个对象,以便从代码中的任何地方访问。这很糟糕,因为如果您决定更改创建/访问对象的方式,则必须更改代码中期望的所有位置,例如,它们应该通过 static 访问它SingletonClass.GetInstance()

此外,当您实施单元测试时,通常需要使用模拟而不是真实对象。在您的情况下,如果您希望对某个模块进行单元测试,并且该模块通过 访问真实的音频输出SingletonClass.GetInstance(),那么用存根替换真实的音频输出将变得非常困难。

另一方面,如果您的模块通过依赖注入获取音频输出对象(例如,作为传递给构造函数的参数),那么在测试时,您可以注入一个实现相同接口的存根,而不是真正的音频输出对象。

当然,在注入此类对象的级别上,您可以使用单例来确保一次只有一个实例。要点是底层代码不应该关心可以有多少对象或如何获取它们 - 它只适用于注入的内容。

因此,作为底线,如果您真的认为需要它,您可以使用 Singleton,但不要让它作为全局状态访问。

于 2012-04-15T23:10:02.317 回答
3

明智地使用设计模式是一个棘手的问题,需要大量练习。

我见过很多人使用 Singleton 只是因为它“有点”适合他们需要做的事情。这通常会导致灾难,例如在多线程环境的情况下,或者就像它旨在隐藏设计缺陷并需要稍后重新设计完整的系统一样。

我想说你在考虑 Singleton 时需要考虑一些事情:

  • 我真的只需要我的对象的一个​​实例吗?我不是在试图隐藏一些设计缺陷吗?
  • 可以全局访问我的对象是否有意义?

但我想说不要花太多时间在它上面:它可能并不总是最好的解决方案,但在某些情况下这仍然是一个可以接受的解决方案,除非你在多线程环境中,否则你会可能很少有问题。这主要是一种设计选择。

如果你想获得更多关于设计模式的知识,我推荐这本书,这几乎是该主题的参考。

于 2012-04-15T22:59:49.000 回答
2

只要:

  • 您不在多线程环境中(多个线程访问单例)
  • 处于多线程环境中并在单例中实施了适当的保护
  • 单例对象未在多个动态加载的模块中定义
于 2012-04-15T22:51:57.053 回答