如果单身人士不好,那为什么一个服务容器好? [英] If Singletons are bad then why is a Service Container good?

查看:113
本文介绍了如果单身人士不好,那为什么一个服务容器好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们都知道坏的单身人士是因为它们隐藏依赖关系,而且其他原因

We all know how bad Singletons are because they hide dependencies and for other reasons.

但是在一个框架中,可能有很多对象需要被实例化一次,并被称为

But in a framework, there could be many objects that need to be instantiated only once and called from everywhere (logger, db etc).

为了解决这个问题,我被告知要使用一个所谓的对象管理器(或服务容器(如symfony))内部存储对服务(记录器等)的所有引用。

To solve this problem I have been told to use a so called "Objects Manager" (or Service Container like symfony) that internally stores every reference to Services (logger etc).

但是,为什么服务提供商不如纯粹的单身人士那样糟糕?

But why isn't a Service Provider as bad as a pure Singleton?

服务提供商也隐藏依赖关系,他们只是包装了第一次的创建。所以我真的很难理解为什么我们应该使用服务提供商而不是单身人士。

Service provider hides dependencies too and they just wrap out the creation of the first istance. So I am really struggling to understand why we should use a service provider instead of singletons.

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

PS. I know that to not hide dependencies I should use DI (as stated by Misko)

我会添加:这些天单身不是那么邪恶,PHPUnit的创建者在这里解释:

I would add: These days singletons aren't that evil, the creator of PHPUnit explained it here:

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

DI + Singleton解决了这个问题:

DI + Singleton solves the problem:

<?php
class Client {

    public function doSomething(Singleton $singleton = NULL){

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

        // ...
    }
}
?>

这是非常聪明的,即使这并不解决所有问题。

that's pretty smart even if this doesn't solve at all every problems.

除了DI和服务容器是否有任何良好的可接受的解决方案来访问此帮助对象?

Other than DI and Service Container are there any good acceptable solution to access this helper objects?

推荐答案

服务定位器只是两个罪恶的一小部分。这四个差异的较小(至少我不能想到任何其他人现在):

Service Locator is just the lesser of two evils so to say. The "lesser" boiling down to these four differences (at least I can't think of any others right now):

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

Service Container does not violate Single Responsibility Principle like Singleton does. Singletons mix object creation and business logic, while the Service Container is strictly responsible for managing the object lifecycles of your application. In that regard Service Container is better.

由于静态,单例通常会被硬编码到应用程序中方法调用,这导致紧耦合和难以模拟的依赖性在你的代码。另一方面,SL只是一个类,它可以被注入。所以当你所有的类都依赖它,至少它是一个松散耦合的依赖。所以除非你将ServiceLocator实现为Singleton本身,那么它的一些更好,也更容易测试。

Singletons are usually hardcoded into your application due to the static method calls, which leads to tight coupled and hard to mock dependencies in your code. The SL on the other hand is just one class and it can be injected. So while all your classed will depend on it, at least it is a loosely coupled dependency. So unless you implemented the ServiceLocator as a Singleton itself, that's somewhat better and also easier to test.

然而,使用ServiceLocator的所有类都将依赖于ServiceLocator,这也是一种耦合形式。这可以通过使用ServiceLocator的接口来缓解,因此您没有绑定到具体的ServiceLocator实现,但是您的类将依赖于某种定位器的存在,而不使用ServiceLocator会大大增加重用。

However, all classes using the ServiceLocator will now depend on the ServiceLocator, which is a form of coupling, too. This can be mitigated by using an interface for the ServiceLocator so you are not bound to a concrete ServiceLocator implementation but your classes will depend on the existence of some sort of Locator whereas not using a ServiceLocator at all increases reuse dramatically.

隐藏依赖关系的问题非常多。当您将定位器注入到您的消费类中时,您不会知道任何依赖关系。但是,与Singleton相反,SL通常将实例化幕后所需的所有依赖。所以当你获取一个服务时,你不会像 Misko在信用卡示例中,例如:您不必手动实例化所有依赖关系。

The problem of hiding dependencies very much exists forth though. When you just inject the locator to your consuming classes, you wont know any dependencies. But in contrast to the Singleton, the SL will usually instantiate all the dependencies needed behind the scenes. So when you fetch a Service, you dont end up like Misko Hevery in the CreditCard example, e.g. you dont have to instantiate all the depedencies of the dependencies by hand.

从实例中获取依赖关系也违反了 Demeter法案,其中规定您不应该挖掘合作者。一个实例只应该与其直接合作者交谈。这是Singleton和ServiceLocator的一个问题。

Fetching the dependencies from inside the instance is also violating Law of Demeter, which states that you should not dig into collaborators. An instance should only talk to its immediate collaborators. This is a problem with both Singleton and ServiceLocator.

全球状态的问题也有一些缓解因为当您在测试之间实例化一个新的服务定位器时,所有先前创建的实例也被删除(除非您犯了错误并将其保存在SL中的静态属性中)。当然,对于由SL管理的课程中的任何全球状态来说,这并不适用。

The problem of Global State is also somewhat mitigated because when you instantiate a new Service Locator between tests all the previously created instances are deleted as well (unless you made the mistake and saved them in static attributes in the SL). That doesnt hold true for any global state in classes managed by the SL, of course.

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

Also see Fowler on Service Locator vs Dependency Injection for a much more in-depth discussion.

有关您的更新和链接的文章的注释由 Sebastian Bergmann使用Singleton的测试代码:Sebastian绝对不会建议所提出的解决方法使得使用Singleons更少是一个问题。这只是使代码无法测试更多可测试的一种方法。但它仍然是有问题的代码。事实上,他明确地指出:只因为你可以,并不意味着你应该。

A note on your update and the linked article by Sebastian Bergmann on testing code that uses Singletons : Sebastian does, in no way, suggest that the proposed workaround makes using Singleons less of a problem. It is just one way to make code that otherwise would be impossible to test more testable. But it's still problematic code. In fact, he explicitly notes: "Just Because You Can, Does Not Mean You Should".

这篇关于如果单身人士不好,那为什么一个服务容器好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆