【发布时间】:2018-12-28 13:43:40
【问题描述】:
我想知道是否有针对以下案例的最佳实践。
例如,我有几个服务并将它们作为一个数组注入到“工厂”服务中。然后我调用这个工厂的一个方法,并且想要只获得一个服务取决于某些条件。之后我执行此服务并获得结果...
但是,其中一些服务需要我从客户请求中获得的随机字符串。
当然,我可以用这个字符串作为参数调用服务的方法,但是有几个服务不需要这个字符串,我会在方法中得到“未使用的变量”。
我想我可以从工厂获得服务,然后调用 setter 将此字符串添加到服务中。但它看起来不像是无状态服务。
是否有更优雅的解决方案来传递我无法注入服务或使用 setter 的参数?
这是我的代码中的样子
首先,我有一个要检查的所有服务器的接口。该服务应该支持客户,然后它应该呈现来自 DTO 的信息。
interface Renderable {
public function supports(Customer $customer);
public function render(CustomerDTO $dto);
}
接下来,我有几个服务。这个使用 DTO 来渲染数据。
class ServiceOne implements Renderable
{
public function suppots(Customer $customer)
{
return $customer->getPriority() === 1;
}
public function render(CustomerDTO $dto)
{
return 'One: '.$dto->getName();
}
}
但是,有些服务不需要任何 DTO 来呈现,它们只是提供一个硬编码的值。
class ServiceTwo implements Renderable
{
public function suppots(Customer $customer)
{
return $customer->getPriority() !== 1;
}
// service does not use DTO, it simply output result
// so, I'll get a notice about unused variable
// and I can not remove it from the method since it is in interface
public function render(CustomerDTO $dto)
{
return 'Two';
}
}
这是一家工厂。它将所有服务作为数组注入。然后它检查并返回支持客户实例的第一个服务。
class ServiceFactory
{
/** @var Renderable[] */
private $services;
public function __construct(iterable $services)
{
$this->services = $services;
}
public function getRenderer(Customer $customer)
{
foreach ($this->services as $service)
{
if ($service->supports($customer)
{
return $service;
}
}
}
}
这里就像我使用工厂及其结果
$customer = ...; // it comes from a database
$request = ...; // it comes from a http request
$renderService = $factory->getRenderer($customer);
$customerDTO = CustomerDTO::createFromData([
'customerUid' => $customer->getUid(),
'date' => new \DateTime(),
'name' => $request->getSheetUid(),
'tags' => $request->getTags(),
]);
$renderService->render($customerDTO);
所以,我必须使用 DTO 实例调用 Renderer::render。但有些服务不使用它来“渲染”数据。我也不能将它注入到渲染器服务中,因为这个对象(DTO)是在所有服务都已经注入时在运行时中构建的。我也无法将 RequestStack 注入服务。
【问题讨论】:
-
如何确定哪些服务需要参数,哪些不需要?你能分享prototype-PHP代码吗?回答你会更容易
-
如果一个服务需要基于请求的信息,那么根据定义,它不再是无状态的。话虽如此,您似乎可以将 RequestStack 注入需要它的服务中,并让它处理随机参数。
-
我同意@Cerad,
RequestStack以干净且可预期的方式解决随机参数。获取方法见Symfony docs。 -
@TomášVotruba,添加了一个代码示例。
-
我明白了。我认为最好的选择是使
render()参数可以为空。其他选项也是可能的,但增加的复杂性多于价值。
标签: symfony dependency-injection