考虑到依赖注入,我应该在哪里构建嵌套逻辑层中的对象?
Considering Dependency Injection, where should I build objects in nested logical layers?
假设我有这样的东西
Controller
使用 Service
.
Service
有 History
、Source
和 HttpClient
.
Source
有 SourceRepository
和 id
。
Source
仅在从 SourceRepository
. 获取信息后对其他对象有用
History
有 HistoryRepository
和 Source
.
下面是 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();
}
}
现在我有一些关于依赖注入的问题:
- 所有对象构建真的应该停留在最高级别,在本例中为
Controller
?
- 或者有部分的对象建筑在中间层的情况?
- 如果我要使用依赖注入容器,我认为它无法实例化
Source
因为 id
。我该如何解决?
在阅读了更多有关依赖注入、控制反转和 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。
假设我有这样的东西
Controller
使用Service
.Service
有History
、Source
和HttpClient
.Source
有SourceRepository
和id
。Source
仅在从SourceRepository
. 获取信息后对其他对象有用
History
有HistoryRepository
和Source
.
下面是 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();
}
}
现在我有一些关于依赖注入的问题:
- 所有对象构建真的应该停留在最高级别,在本例中为
Controller
?- 或者有部分的对象建筑在中间层的情况?
- 如果我要使用依赖注入容器,我认为它无法实例化
Source
因为id
。我该如何解决?
在阅读了更多有关依赖注入、控制反转和 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。