简体   繁体   English

依赖注入容器和 Collections

[英]Dependency Injection Container and Collections

I have been searching for an answer in this topic but I haven't been able to find a satisfactory one like in other topics, where the consensus is solid.我一直在寻找这个主题的答案,但我无法像其他主题一样找到令人满意的答案,共识是稳固的。

The situation情况

To keep things simple: I am implementing a custom Dependency Injection Container into one of my current projects (I know, I should use an already built one, but I'm doing it with learning purposes; so answers like 'use this func of that container…' are not useful) and I've stumbled a problem with instantiation of new elements inside a collection.为了简单起见:我正在将一个自定义依赖注入容器实现到我当前的一个项目中(我知道,我应该使用一个已经构建的容器,但我这样做是出于学习目的;所以像“使用这个函数”这样的答案容器...' 没用),我偶然发现了一个在集合中实例化新元素的问题。

The problem问题

Imagine that I have a complex object, for example a car.想象一下,我有一个复杂的 object,例如一辆汽车。 This car has several dependencies (engine, axis, seats, airbags…) that have, at the same time, their own dependencies, and so on.这辆车有几个依赖项(发动机、轴、座椅、安全气囊……),它们同时具有它们自己的依赖项,等等。 It is not a big issue to make the DiC (via autowiring or using a config file) build the object graph and inject all the dependencies with a simple line of code like:让 DiC(通过自动装配或使用配置文件)构建 object 图并使用简单的代码行注入所有依赖项并不是什么大问题,例如:

$car = $container->get(‘car’);

The problem arrives when I build a CarCollection, which is a simple class that wraps an array of cars.当我构建一个 CarCollection 时问题就来了,它是一个简单的 class,它包含了一系列汽车。 The issue comes when I try to use a method that populates the collection with all the cars that exist in the database.当我尝试使用一种使用数据库中存在的所有汽车填充集合的方法时,问题就出现了。 It's obvios that the collection should be able to create the Car objects on the fly when we call the “getAll” method from the database.很明显,当我们从数据库中调用“getAll”方法时,该集合应该能够动态创建 Car 对象。 The code would be something like this:代码将是这样的:

public function populate(array $filters) {
    $all_data = $this->dao->getAll($filters); // Call the data access object to query all cars.
    foreach($all_data as $data) {
        $new_object = $this->container(‘car’); // create a template object
        $new_object->setData($data); // set the info.
        $this->items[] = $new_object; // Add to the collection.
     }
}

If car was not such a complex object it would be easier, because I could pass the car fqcn as a parameter for carCollection and use it in every iteration.如果 car 不是那么复杂的 object 会更容易,因为我可以将 car fqcn 作为 carCollection 的参数传递并在每次迭代中使用它。 But that's not possible for a very complex object (or if I want to instantiate different sub types of the object - for example: lorry, pick-up, van…- depending on information from the database).但这对于非常复杂的 object 是不可能的(或者如果我想实例化 object 的不同子类型 - 例如:货车,皮卡,货车...... - 取决于数据库中的信息)。

The question.问题。

Regarding the collection being aware about the container: does not it break the purpose of the DIC phylosophy?关于收集对容器的了解:它不会破坏 DIC 哲学的目的吗?

I guess not on one side, because I am using PSR\Container to type hint the container I pass to the collection (which loosens the coupling).我猜不是一方面,因为我使用 PSR\Container 来输入提示我传递给集合的容器(这会放松耦合)。 But it breaks the idea that the container should not be coupled with the domain model at all.但它打破了容器根本不应该与域 model 耦合的想法。

The only alternative that I have thought about is substituting the creation of one new object for each iteration with a cloning from a prototype object that lives in the collection as a property.我想到的唯一替代方法是用从作为属性存在于集合中的原型 object 的克隆替换为每次迭代创建一个新的 object。 But we all know cloning in php can get really tricky and very difficult to debug (Or worse: very difficult to even know that there is a problem going on).但是我们都知道在 php 中进行克隆会变得非常棘手并且非常难以调试(或者更糟糕的是:甚至很难知道正在发生问题)。

Similar issue.类似的问题。

PS: I have the same problem when I try to do lazy loading using Porxy objects: I need the proxy objects to have access to the container if I want to instantiate the full object later, which also breaks the principles of a DiC. PS:当我尝试使用 Porxy 对象进行延迟加载时,我遇到了同样的问题:如果我想稍后实例化完整的 object,我需要代理对象来访问容器,这也违反了 DiC 的原则。

Thank you all.谢谢你们。

I think the core of your issue comes down to this:我认为您的问题的核心归结为:

The issue comes when I try to use a method that populates the collection with all the cars that exist in the database.当我尝试使用一种使用数据库中存在的所有汽车填充集合的方法时,问题就出现了。

The composition of object graphs of application components should be independent of any I/O, as described here and here by Mark Seemann.应用程序组件的object组成应独立于任何 I/O,如 Mark Seemann 所述。 This means that the structure of those object graphs can't (and shouldn't) change based on changes in your database.这意味着那些 object 图的结构不能(也不应该)根据数据库的变化而改变。

It seems to me that your Car object is a Domain Object, rather than a (Domain) Service.在我看来,您的Car object 是域 Object,而不是(域)服务。 It would, therefore, be better suited to return a collection of Car instances from a service, rather than injecting the collection directly into one of your application components.因此,它更适合从服务返回Car实例的集合,而不是将集合直接注入您的应用程序组件之一。

I need the proxy objects to have access to the container if I want to instantiate the full object later, which also breaks the principles of a DiC.如果我想稍后实例化完整的 object,我需要代理对象来访问容器,这也违反了 DiC 的原则。

It's generally considered to be a bad practice to let application code depend on the DI Container.通常认为让应用程序代码依赖于 DI 容器是一种不好的做法。 This aa pattern known as the Service Locator anti-pattern .这种模式称为服务定位器反模式 There are many reasons why Service Locator is considered to be a bad idea, but it's important to understand that the list of downsides of Service Locator do not apply when the DI Container is used in the application's startup path (aka the Composition Root ). Service Locator 被认为是一个坏主意的原因有很多,但重要的是要了解,当 DI 容器用于应用程序的启动路径(也称为Composition Root )时,Service Locator 的缺点列表并不适用。 A DI Container used within the Composition Root, is not an implementation of the Service Locator anti-pattern.组合根中使用的 DI 容器不是服务定位器反模式的实现。

When your proxy classes are defined within the Composition Root, it's perfectly fine to let them depend on the DI Container and you won't violate any software principle or practice.当您的代理类组合根中定义时,让它们依赖于 DI 容器是完全可以的,并且您不会违反任何软件原则或实践。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM