我在服务层的应用程序中遇到依赖性问题。
我有以下课程:
<?php
class UserService{
private $userRepository;
private $vocationService;
private $roleService;
public function __construct(UserRepository $userRepository, VocationService $vocationService, RoleService $roleService)
{
$this->userRepository = $userRepository;
$this->vocationService = $vocationService;
$this->roleService = $roleService;
}
}
我只注射了三个依赖项。 假设,我想添加下一个依赖项,例如:NextService。 我的构造函数会再次增长。
如果我想在构造函数中传递更多依赖项,该怎么办?
也许我应该通过传递IoC容器然后获得理想的类来解决这个问题? 这是一个例子:
<?php
class UserService{
private $userRepository;
private $vocationService;
private $roleService;
public function __construct(ContainerInterface $container)
{
$this->userRepository = $container->get('userRepo');
$this->vocationService = $container->get('vocService');
$this->roleService = $container->get('roleService');
}
}
但是现在我的 UserService 类依赖于我正在注入的IoC容器。
如何按照良好做法解决问题?
问候,亚当
答案 0 :(得分:8)
出于多种原因,将容器作为服务依赖项注入被视为不良做法。我认为这里的要点是找出原因,然后尝试理解导致您将“注入容器”作为可能解决方案以及如何解决此问题的问题。
在object oriented programming中,明确定义对象之间的关系非常重要。当您查看给定的对象依赖项时,应该直观地了解对象的行为方式以及通过查看其公共API所依赖的其他对象。
让对象依赖a dependency resolver也是一个坏主意,在您共享的示例中,如果没有DI component提供的container
,您的对象就无法生存。
如果要在其他地方使用该对象,例如在使用其他框架的应用程序中,则必须重新考虑对象获取其依赖关系并重构它的方式。
这里的主要问题是了解您的服务需要所有这些依赖项的原因,
在object-oriented programming,single responsibility principle 说明每个上下文(类,函数,变量等)都应该 确定单一责任,责任应该是 完全由上下文封装。它的所有服务都应该是 与该责任严格一致。 来源:维基百科
根据这个定义,我认为您应该将UserService
拆分为分别处理只有一个责任的服务。
答案 1 :(得分:1)
我同意__construct
可以变得相当容易。
但是,您可以使用Setter DI
:http://symfony.com/doc/current/components/dependency_injection/types.html#setter-injection
Morover,有一个Property DI
,但我不会推荐它,因为你的服务可以随意操纵:http://symfony.com/doc/current/components/dependency_injection/types.html#property-injection
答案 2 :(得分:0)
您可以在一个帮助程序服务中抽象一些常用服务,然后将此帮助程序注入其他服务。您还可以在此帮助程序服务中定义一些有用的函数。像这样:
<?php
namespace Saman\Library\Service;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Form\FormFactory;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
use Symfony\Bundle\TwigBundle\Debug\TimedTwigEngine;
use Symfony\Component\Security\Core\SecurityContext;
use Doctrine\ORM\EntityManager;
class HelperService
{
protected $translator;
protected $securityContext;
protected $router;
protected $templating;
protected $em;
public function __construct(
Translator $translator,
SecurityContext $securityContext,
Router $router,
TimedTwigEngine $templating,
EntityManager $em
)
{
$this->translator = $translator;
$this->securityContext = $securityContext;
$this->router = $router;
$this->templating = $templating;
$this->em = $em;
}
Getters ...
public function setParametrs($parameters)
{
if (null !== $parameters) {
$this->parameters = array_merge($this->parameters, $parameters);
}
return $this;
}
/**
* Get a parameter from $parameters array
*/
public function getParameter($parameterKey, $defaultValue = null)
{
if (array_key_exists($parameterKey, $this->parameters)) {
return $this->parameters[$parameterKey];
}
return $defaultValue;
}
}
现在假设您有一个UserService,然后您可以这样定义:
<?php
namespace Saman\UserBundle\Service;
use Saman\Library\Service\HelperService;
class UserService
{
protected $helper;
public function __construct(
Helper $helper,
$parameters
)
{
$this->helper = $helper;
$this->helper->setParametrs($parameters);
}
public function getUser($userId)
{
$em = $this->helper->getEntityManager();
$param1 = $this->helper->getParameter('param1');
...
}