当前位置: 首页 > 面试题库 >

如果Singletons不好,那么服务容器为什么好?

林雅畅
2023-03-14
问题内容

我们都知道 单身 人士有多 糟糕
,因为他们隐藏了依赖关系以及其他原因。

但是在一个框架中,可能有许多对象只需要实例化一次,并可以 从任何地方 调用(记录器,数据库等)。

为了解决这个问题,有人告诉我使用所谓的“对象管理器”(或诸如symfony之类的服务容器),在内部存储对服务(记录器等)的所有引用。

但是,为什么服务提供者不像单纯的Singleton那样糟糕?

服务提供者也隐藏了依赖关系,它们只是包装了第一个实例的创建。因此,我真的很难理解为什么我们应该使用服务提供商而不是单例。

PS。我知道不要隐藏依赖项,我应该使用DI(如Misko所述)

我要补充一点:如今,单例并没有那么邪恶,PHPUnit的创建者在这里对此进行了解释:

  • http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html

DI + Singleton解决了以下问题:

<?php
class Client {

    public function doSomething(Singleton $singleton = NULL){

        if ($singleton === NULL) {
            $singleton = Singleton::getInstance();
        }

        // ...
    }
}
?>

即使这不能解决所有问题,这还是很聪明的。

除了DI和Service Container 之外,还有什么好的可接受的 解决方案来访问此帮助对象?


问题答案:

可以这么说,服务定位器只是两个弊端中的较小者。归结为这四个差异的“较小”( 至少我现在无法想到其他任何 差异):

单一责任原则

服务容器不违反Singleton那样的单一责任原则。单例混合了对象创建和业务逻辑,而服务容器严格负责管理应用程序的对象生命周期。在这方面,服务容器更好。

耦合

由于静态方法调用,单例通常被硬编码到您的应用程序中,这导致代码中的紧密耦合和难以模拟的依赖关系。另一方面,SL只是一类,可以注入。因此,尽管您所有的分类都将依赖它,但至少它是一个松散耦合的依赖关系。因此,除非您将ServiceLocator本身实现为Singleton,否则它会更好并且也更容易测试。

但是,所有使用ServiceLocator的类现在都将依赖于ServiceLocator,这也是一种耦合形式。可以通过使用ServiceLocator的接口来减轻这种情况,因此您不必绑定到具体的ServiceLocator实现,但是您的类将取决于某种Locator的存在,而根本不使用ServiceLocator会大大提高重用性。

隐藏的依赖

但是,非常存在隐藏依赖项的问题。当您仅将定位符注入到使用的类中时,您将不知道任何依赖项。但是与Singleton相比,SL通常会实例化幕后所需的所有依赖关系。因此,当您获取服务时,最终不会像CreditCard示例中的Misko
Hevery
那样结束,例如,您不必手动实例化依赖项的所有依赖关系。

从实例内部获取依赖关系也违反了Demeter定律,该定律指出您不应该深入研究协作者。实例只应与其直接的协作者交谈。Singleton和ServiceLocator都存在此问题。

全球状态

全局状态的问题也有所缓解,因为在测试之间实例化新的服务定位器时,所有先前创建的实例也会被删除(除非您犯了错误,并将其保存在SL的静态属性中)。当然,这对于SL管理的类中的任何全局状态都不成立。

另请参阅关于服务定位器与依赖注入的
Fowler的更深入讨论。

关于您的更新的注释以及Sebastian Bergmann关于使用Singletons的测试代码的链接文章:Sebastian丝毫没有暗示所建议的解决方法使使用Singleons的问题减少了。这只是使代码无法进行测试的一种方法。但这仍然是有问题的代码。实际上,他明确指出:“仅仅因为您可以,并不意味着您应该这样做”。



 类似资料:
  • 问题内容: 我正在编写一个脚本,该脚本应该在一堆服务器周围运行,并从其中选择一堆数据,包括本地服务器。选择所需数据的SQL非常复杂,因此我正在编写临时视图,并使用OPENQUERY语句获取数据,因此最终我最终循环了如下语句: 但是,我听说在本地服务器上使用OPENQUERY是一种皱眉。有人能详细说明为什么吗? 问题答案: 尽管查询可能返回多个结果集,但OPENQUERY仅返回第一个结果集。 OPE

  • 本文向大家介绍为什么我们需要微服务容器?相关面试题,主要包含被问及为什么我们需要微服务容器?时的应答技巧和注意事项,需要的朋友参考一下 要管理基于微服务的应用程序,容器是最简单的选择。它帮助用户单独部署和开发。您还可以使用Docker将微服务封装到容器的镜像中。没有任何额外的依赖或工作,微服务可以使用这些元素。

  • 问题内容: 对这个重复的问题表示歉意,但是我还没有找到满意的答案。大多数问题都有自己的特定用例: Java- 替代thread.sleep在Java中,是否有任何更好的替代方法来跳过/避免使用Thread.sleep(1000)? 我的问题是针对非常通用的用例。等待条件完成。做一些操作。检查条件。如果条件不成立,请等待一段时间,然后再次执行相同的操作。 例如,考虑一种通过调用其createAPI表

  • 问题内容: 我所读到的有关更好的PHP编码实践的所有内容都一直在说不要使用,因为速度太快。 为什么是这样? 做相同的事情的正确/更好的方法是什么?如果有关系,我正在使用PHP 5。 问题答案: 并且都要求系统会记录本已被列入什么/需要的。每个呼叫都意味着检查该日志。因此,肯定 有一些 额外的工作要做,但足以损害整个应用程序的速度吗? …我真的对此表示怀疑…除非您使用的是 真正的 旧硬件或经常这样做

  • 本文向大家介绍RetinaNet为什么比SSD效果好相关面试题,主要包含被问及RetinaNet为什么比SSD效果好时的应答技巧和注意事项,需要的朋友参考一下 参考回答: SSD 在训练期间重新采样目标类和背景类的比率,这样它就不会被图像背景淹没。RetinaNet采用另一种方法来减少训练良好的类的损失。因此,只要该模型能够很好地检测背景,就可以减少其损失并重新增强对目标类的训练。所以Retina

  • 本文向大家介绍kafka 为什么那么快?相关面试题,主要包含被问及kafka 为什么那么快?时的应答技巧和注意事项,需要的朋友参考一下 Cache Filesystem Cache PageCache缓存 顺序写 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快。 Zero-copy 零拷技术减少拷贝次数 Batching of Messages 批量量处理。合并小