服务中的许多依赖项

时间:2014-10-31 16:43:21

标签: php symfony dependency-injection inversion-of-control symfony-2.5

我在服务层的应用程序中遇到依赖性问题。

我有以下课程:

   <?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容器。

如何按照良好做法解决问题?

问候,亚当

3 个答案:

答案 0 :(得分:8)

出于多种原因,将容器作为服务依赖项注入被视为不良做法。我认为这里的要点是找出原因,然后尝试理解导致您将“注入容器”作为可能解决方案以及如何解决此问题的问题。

object oriented programming中,明确定义对象之间的关系非常重要。当您查看给定的对象依赖项时,应该直观地了解对象的行为方式以及通过查看其公共API所依赖的其他对象。

让对象依赖a dependency resolver也是一个坏主意,在您共享的示例中,如果没有DI component提供的container,您的对象就无法生存。 如果要在其他地方使用该对象,例如在使用其他框架的应用程序中,则必须重新考虑对象获取其依赖关系并重构它的方式。

这里的主要问题是了解您的服务需要所有这些依赖项的原因,

  

object-oriented programmingsingle responsibility principle   说明每个上下文(类,函数,变量等)都应该   确定单一责任,责任应该是   完全由上下文封装。它的所有服务都应该是   与该责任严格一致。   来源:维基百科

根据这个定义,我认为您应该将UserService拆分为分别处理只有一个责任的服务。

  • 获取用户并将其保存到dababase的服务,例如
  • 管理角色的另一项服务,例如
  • ......等等

答案 1 :(得分:1)

我同意__construct可以变得相当容易。

但是,您可以使用Setter DIhttp://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');
     ... 
  }