Множество зависимостей в обслуживании

У меня проблемы с зависимостями в моем приложении на уровне сервиса.

У меня есть следующий класс:

   <?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, который я добавляю.

Как решить проблему, следуя передовой практике?

С уважением, Адам

1

Решение

Внедрение контейнера в качестве зависимости от вашего сервиса считается плохой практикой по нескольким причинам. Я думаю, что главное здесь — выяснить, почему, а затем попытаться понять проблему, которая заставляет вас думать о «впрыскивании контейнера» как возможном решении, и о том, как решить эту проблему.

В объектно-ориентированное программирование, важно четко определить отношения между объектами. Когда вы смотрите на зависимости данного объекта, вам должно быть интуитивно понятно, как объект ведет себя и каковы другие объекты, на которые он опирается, глядя на его общедоступный API.

Это также плохая идея, чтобы позволить вашему объекту полагаться на средство разрешения зависимостей, В примере, которым вы поделились, ваш объект не может жить без container который предоставляется DI компонент.
Если вы хотите использовать этот объект в другом месте, например, в приложении, которое использует другую платформу, вам придется переосмыслить способ, которым ваш объект получает свои зависимости, и реорганизовать его.

Основная проблема здесь состоит в том, чтобы понять, почему вашему сервису нужны все эти зависимости,

В объектно-ориентированное программирование, принцип единой ответственности
утверждает, что каждый контекст (класс, функция, переменная и т. д.) должен
определить единую ответственность, и эта ответственность должна быть
полностью инкапсулирован контекстом. Все его услуги должны быть
тесно связаны с этой ответственностью.
Источник: Википедия

Исходя из этого определения, я думаю, что вы должны разделить UserService в услуги, которые обрабатывают только один Ответственность каждого.

  • Сервис, который выбирает пользователей и сохраняет их в вашей базе данных, например
  • Другой сервис, который управляет ролями, например
  • … и так далее
8

Другие решения

я согласна с тем что __construct может расти довольно легко.

Тем не менее, у вас есть Setter DI к вашим услугам: http://symfony.com/doc/current/components/dependency_injection/types.html#setter-injection

Более того, есть Property DI, но я бы не рекомендовал его, так как ваш сервис остается открытым для манипуляций: http://symfony.com/doc/current/components/dependency_injection/types.html#property-injection

1

Вы можете абстрагировать некоторые часто используемые службы в одном вспомогательном сервисе, а затем просто добавить этот помощник в другие сервисы. Также вы можете определить некоторые полезные функции в этом вспомогательном сервисе. Что-то вроде этого:

<?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');
...
}
0
По вопросам рекламы [email protected]