避免单一项和全局变量-但是缓存、提供程序、控制器.



我目前正在通过阅读书籍、网络文章和观看视频来"更新"我的开发知识,尤其是关于TDD原理的知识。到处都会弹出一个警告,不要使用全局状态变量,因为它们会使系统变得脆弱,不太容易测试,而且由于单态并没有好到哪里去,或者更确切地说是一样的,也不要使用它们。

现在我想知道:我真的能在这件事上保持一致吗?

  • 那么应用程序使用的缓存呢?这样它就不必一次又一次地查找频繁使用的数据库对象了?我需要传递该缓存的一个实例,否则有什么意义
  • 另一个例子是DAO,或者我们称之为提供者。他们什么也不做,只是为我们提供JPA数据库访问,但在其他方面没有状态。那么,为什么不让他们单身呢
  • 网络前端的控制器呢?他们所做的只是对请求做出反应——同样没有内部状态

一次又一次地实例化后两者不会浪费很多性能吗?我相信还有更多这样的例子。

也许可以使用singleton,只要它们除了韵母之外没有任何成员变量?

即使它们有成员变量,但所有这些变量都被注入其中,也应该保存为使用它们,因为任何对象,无论是否为单例,都可以修改注入的对象,所以这真的没有任何区别。

我对这整个"避免单身"的业务有点困惑,我甚至不确定自己是否完全理解其中的风险。但最重要的是,我想听听对以上示例的看法,因为这些是我们应用程序中使用singleton最常见的地方。

谢谢!

顺便说一句:我们使用的是springs依赖注入,所以如何做到这一点不是我的问题,而是为什么要避免它以及在哪里可以。

Singleton的问题与其说是Singleton设计模式本身,不如说是它们在整个应用程序中被过度使用为有状态的全局God对象。

这种使用方式有两个主要缺点:

  • singleton上的依赖项是隐藏的依赖项,对象与它们紧密耦合,这阻碍了代码的可发现性、可维护性和可测试性。

  • 对象依赖于singleton,它们不知道自己处于哪个状态。singleton的行为在这里和那里使用的顺序开始变得重要,并且你开始看到"MySingleton.Initialize()"到处都是,这很危险,并且破坏了拥有单个实例的整个目的。

只有超越这些陷阱的单实例才是IMO值得考虑的——这意味着无状态、不可变的对象以某种方式被注入到消费者中,并可以用具有相同合同的其他实例替换。

除此之外,Singleton化通常是应用于错误对象的过早优化。

这篇博客文章大致概括了这一点:http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx

您是绝对正确的——有些情况下需要单个实例。然而,"避免单身"业务并没有说明他们不需要。在我的理解中,它指出单例行为应该由依赖容器添加,而不是由静态实例添加。

这将允许您在单元测试中模拟它,同时在生产中只有一个实例。您可能会发现此链接很有用:Ninject 中的对象范围

单态和全局变量的问题是我们需要它们,但大多数编程语言只提供一个"全局"上下文。

想象一下,你可以这样做:

 Global g1 = new Global();
 g1.run( ... some code ... );
 Global g2 = new Global();
 g2.run( ... some code ... );

当代码由g2运行时,运行g1的singleton和globals都不可见。这实际上就是我们想要的:一种高效的方式来说"好吧,我已经完成了全局变量和其他东西,去掉它们"。

解决方案是一个工厂,它可以为您构建所有的singleton和global,并将它们放在正确的位置放入代码中。然后,您可以根据需要在测试中创建这个工厂的新实例(以及新的singleton和globals)

这就是"依赖项注入"的全部内容。这是一个简短的介绍。

最新更新