【发布时间】:2011-08-27 10:40:23
【问题描述】:
我们都知道糟糕的单例有多糟糕,因为它们隐藏了依赖关系并且对于other reasons。
但在框架中,可能有许多对象只需要实例化一次并从任何地方调用(记录器、数据库等)。
为了解决这个问题,有人告诉我使用所谓的“对象管理器”(或 Service Container,如 symfony),它在内部存储对服务(记录器等)的每个引用。
但是为什么服务提供者不像纯单例那样糟糕呢?
服务提供者也隐藏了依赖关系,它们只是包装了第一个实例的创建。所以我真的很难理解为什么我们应该使用服务提供者而不是单例。
PS。我知道为了不隐藏依赖项,我应该使用 DI(如 Misko 所述)
添加
我要补充一点:现在单身人士并不那么邪恶,PHPUnit 的创建者在这里解释了它:
DI + Singleton 解决问题:
<?php
class Client {
public function doSomething(Singleton $singleton = NULL){
if ($singleton === NULL) {
$singleton = Singleton::getInstance();
}
// ...
}
}
?>
这很聪明,即使这不能解决所有问题。
除了 DI 和服务容器还有什么好的可接受的解决方案来访问这个帮助对象吗?
【问题讨论】:
-
@yes 您的编辑做出了错误的假设。 Sebastian 绝不表示代码 sn-p 正在减少使用 Singleons 的问题。这只是使无法测试的代码更具可测试性的一种方法。但这仍然是有问题的代码。事实上,他明确指出:“仅仅因为你可以,并不意味着你应该”。正确的解决方案仍然是根本不使用单例。
-
@yes 遵循 SOLID 原则。
-
我对单身不好的说法提出异议。它们可能被滥用,是的,但 any 工具也是如此。手术刀可用于挽救生命或结束生命。电锯可以清除森林以防止丛林大火,或者如果您不知道自己在做什么,它可以切断您手臂的相当大一部分。学会明智地使用你的工具,不要把建议当成福音——那是不加思索的头脑。
-
@paxdiablo 但他们 很糟糕。单例违反 SRP、OCP 和 DIP。它们将全局状态和紧密耦合引入您的应用程序,并使您的 API 对它的依赖项撒谎。所有这些都会对代码的可维护性、可读性和可测试性产生负面影响。在极少数情况下,这些缺点超过了一点点好处,但我认为在 99% 的情况下你不需要 Singleton。尤其是在 PHP 中,Singleton 只对 Request 是唯一的,而且从 Builder 中组装协作者图非常简单。
-
不,我不这么认为。工具是执行功能的一种手段,通常是通过某种方式使其变得更容易,尽管有些(emacs?)具有使其更难的罕见区别:-) 在这方面,单例与平衡树或编译器没有什么不同.如果您只需要确保一个对象的一个副本,那么单例会执行此操作。它是否做得好可以争论,但我不相信你可以争辩说它根本没有做到这一点。并且可能有更好的方法,例如电锯比手锯更快,或者钉枪与锤子。这不会使手锯/锤子不再是一种工具。
标签: php oop design-patterns frameworks