2

假设您有一个与数据库交互的系统。由于系统大量使用数据库,几乎每个子程序都遵循这种模式:

foo(database, rest, of, arguments)

这很快就被注意到了,因为 foo 是一个更大对象的一部分,所以连接变量被移动到一个对象变量中。不幸的是,这意味着每个模型对象的构造函数都接受这个参数。

因此,您决定创建一个可以生成与数据库的连接的模块。由于与数据库的连接成本很高,因此连接被缓存,并且该缓存值在以后的调用中返回。

你刚刚创建的是一个单例。这是开发社区中普遍反对的一种模式。再说一次,DRY 是一个受到鼓励的原则,甚至比不鼓励单例模式更是如此。

那么哪个更好呢?您的选择是增加进入每个函数调用(或至少是构造函数)的参数数量,或者创建一个单例。有没有我没有看到的第三种选择?

编辑:反对单身人士的文章是http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx。我认为那里提出的论点是有道理的,我希望反单例阵营能够解决这个设计问题。

4

3 回答 3

2

DRY比“不要使用单例”更重要,如果任何人都真正阐明了任何这样的原则(而不是说,“不要严重滥用单例”)。如果可以,也可以随意满足,但如果只能满足一个,请满足 DRY。

于 2012-07-13T19:49:29.400 回答
1

您还可以考虑查找或注入模式。使用连接详细信息创建一个单例,然后让任何需要连接的类使用“查找”或创建一个系统将其注入到您的类中。如果滥用都可能导致问题,但对于共享资源,这些方法对我来说很有意义。

于 2012-07-13T19:51:41.830 回答
0

当用作将全局变量引入系统的一种方式时,单例被认为是不好的。

作为static变量实现的单例是不好的,因为它们不容易被模拟出来进行测试。由于是静态的,它们不会被注入,从而隐藏了依赖关系。您现在进行的讨论是由您在整个代码中看到这种依赖关系引起的。这太棒了!您正在聆听代码并通过尝试找到更好的设计来做出反应。如果该数据库访问是通过静态入口点进行的,您就不会注意到依赖性的扩散。

使用类的单个共享实例(通常作为服务)的多个对象的概念是完全有效的设计。以这种方式考虑,所有服务对象最终都成为一种“作用域单例”。IE 在这个子系统中只有一个 X 实例。正确实现这是一个连线决策,而不是类实现决策。IE 你可以使用任何类作为单例,只需制作一个并将相同的实例传递给任何想要一个的人......有问题的类不知道它是一个单例。

我同意你的观点,将“数据库”传递给很多对象是一种气味。我会将所有对“数据库”的调用分解为强类型的存储库对象,每个对象都有一个干净的接口,让调用者可以请求它想要的数据集,而不必担心如何检索这些数据或将其转换为域对象。然后,我会将所需的存储库注入之前使用数据库的类的构造函数中,而不是在每次调用时传递它。如果您正在执行“依赖注入”,您会发现接线代码移到您的对象之外,进入工厂类。然后,这些工厂只会将存储库注入到实际需要查询存储库的类中。

我见过的一种模式是对象获得了他们并不真正需要的依赖项,因为它们又将其传递给他们创建的其他对象。这可以通过将这种“工厂”行为分解到它自己的类中来防止。

无论如何..简短的回答是“继续挖掘..找出为什么这么多类需要数据库访问,应用单一责任原则和依赖注入来限制传播”。

于 2012-07-23T22:56:31.443 回答