单例模式是GoF模式书中一个完全付费的成员,但最近它似乎被开发人员世界孤立了。我仍然使用了相当多的单线程,特别是对于工厂类,虽然你必须对多线程问题(像任何类一样)小心一点,但我不明白为什么它们如此糟糕。
Stack Overflow似乎特别假设每个人都认为Singleton是邪恶的。为什么?
请用“事实、参考资料或具体专业知识”来支持您的回答
单例模式是GoF模式书中一个完全付费的成员,但最近它似乎被开发人员世界孤立了。我仍然使用了相当多的单线程,特别是对于工厂类,虽然你必须对多线程问题(像任何类一样)小心一点,但我不明白为什么它们如此糟糕。
Stack Overflow似乎特别假设每个人都认为Singleton是邪恶的。为什么?
请用“事实、参考资料或具体专业知识”来支持您的回答
当前回答
因为它们基本上是面向对象的全局变量,所以通常可以用这样的方式设计类,这样就不需要它们了。
其他回答
当几个人(或团队)达成类似或相同的解决方案时,就会出现一种模式。许多人仍然使用原始形式的单件或使用工厂模板(Alexandrescu的《现代C++设计》中有很好的讨论)。并发性和管理对象生存期的困难是主要障碍,前者很容易按照您的建议进行管理。
和所有的选择一样,辛格尔顿也有其沉浮的部分。我认为它们可以适度使用,特别是对于在应用程序寿命期内仍然存在的对象。事实上,它们类似于(而且很可能是)全球性的,这可能引发了纯粹主义者。
单例使用静态方法实现。静态方法是做单元测试的人所避免的,因为它们不能被嘲笑或拒绝。这个网站上的大多数人都是单元测试的支持者。避免这种情况的最普遍接受的惯例是使用控制模式反转。
单身者解决了一个(而且只有一个)问题。
资源争夺。
如果你有一些资源
(1) 只能有一个实例,并且
(2) 您需要管理单个实例,
你需要一个单身汉。
例子不多。日志文件是最大的文件。您不想只放弃一个日志文件。您希望正确刷新、同步和关闭它。这是必须管理的单个共享资源的示例。
你很少需要单身汉。他们之所以不好,是因为他们觉得自己是一个全球性的人,而且他们是GoF设计模式书的全额付费成员。
当你认为你需要一个全局,你可能犯了一个可怕的设计错误。
这并不是说单体本身是坏的,而是GoF设计模式是坏的。唯一真正有效的论点是,GoF设计模型不适合测试,尤其是在并行运行测试的情况下。
只要在代码中应用以下方法,使用类的单个实例就是有效的构造:
确保将用作单例的类实现了一个接口。这允许使用相同的接口实现存根或模拟确保Singleton是线程安全的。这是给的。单例应该是简单的,而不是过于复杂。在应用程序的运行时,如果需要将单例传递给给定对象,请使用构建该对象的类工厂,并让类工厂将单例实例传递给需要它的类。在测试期间,为了确保确定性行为,将单例类创建为单独的实例,作为实际类本身或实现其行为的存根/模拟,并将其原样传递给需要它的类。不要使用在测试期间创建需要单例的被测对象的类因子,因为它将传递其单个全局实例,这违背了目的。
我们已经在我们的解决方案中使用了Singleton,并取得了巨大的成功,这些成功是可测试的,确保了并行测试运行流中的确定性行为。
单线态的问题是范围增加,因此耦合的问题。不可否认,在某些情况下,您确实需要访问单个实例,并且可以通过其他方式实现。
我现在更喜欢围绕控制反转(IoC)容器进行设计,并允许容器控制生命周期。这为依赖于实例的类提供了好处,使它们不知道存在单个实例的事实。将来可以更改单例的生存期。我最近遇到的一个例子是从单线程到多线程的简单调整。
FWIW,如果你尝试单元测试它时它是一个PIA,那么当你尝试调试、修复或增强它时,它就会变成PIA。