考虑到依赖注入,我应该在哪里构建嵌套逻辑层中的对象?

Considering Dependency Injection, where should I build objects in nested logical layers?

假设我有这样的东西

下面是 PHP + 伪代码(为简单起见)的混合来说明这种情况。

public class Source
{
    ...
    public function __construct(InterfaceRepository $repository, int $id)
    {
        $this->data = $this->repository->findById($id);
    }
}

public class History
{
    ...
    public function __construct(InterfaceRepository $repository, InterfaceSource $source)
    {
        ...
    }

    public function hasHistory(): bool
    {
        return $this->repository->exists($this->source->data);
    }

    public function duplicateHistory()
    {
        ...
    }

}

public class Service
{
    ...
    public function __construct(InterfaceHistory $history, InterfaceSource $source, InterfaceHttpClient $httpClient)
    {
        ...
    }

    public function send()
    {
        if ($this->history->hasHistory()) {
            return $this->history->duplicateHistory();
        }

        return $this->sendNewRequest();
    }

    public function sendNewRequest()
    {
        $this->httpClient->postRequest($this->source->data);
    }
}

public class Controller
{
    public function doSomething(int $id)
    {
        $sourceRepository = new SourceRepository();
        $source = new Source($sourceRepository, $id);

        $historyRepository = new HistoryRepository();
        $history = new History($historyRepository, $source);

        $httpClient = new Guzzle();

        $service = new Service($history, $source, $httpClient);
        $service->send();
    }
}

现在我有一些关于依赖注入的问题:

在阅读了更多有关依赖注入、控制反转和 Composition Root(顺便说一句,@Steven 建议阅读的内容非常棒)之后,我明白了在我的案例中必须做什么。

所以关于我的问题:

Should all object building really stay in the highest level, in this case the Controller?

关于最高级别的部分是正确的,其余部分是错误的。 对象构建 也称为对象图 的最佳位置是在Composition Root 中非常接近应用程序的入口点 and/or 特定路由。

Composition Root 是一个逻辑层,它的唯一职责是组合对象图。它可能是一个单独的 class and/or 函数。虽然它可能与另一个东西在同一个文件中,但它仍然是一个单独的层。 (再次阅读 this link)。

所以在我的例子中,我要做的是在我到达控制器之前,我将创建一个单独的 Composition class 来创建所有必要的东西并仅将 Service 注入 Controller,因此它可以调用 $service->send().


If I was to use a Dependency Injection Container, I think it wouldn't be able to instantiate Source because of id. How should I solve this?

不正确。依赖注入容器确实有办法使用动态参数(例如标量值或其他)实例化 classes。