Сервисный контейнер и заводы одновременно

Это мой первый пост, так что если я что-то делаю не так, поправьте меня 🙂

Я читаю много постов (не только о stackoverflow) и знаю, что внедрение зависимостей — верный способ написания кода. Но я нигде не нахожу информации, исключает ли использование контейнера зависимости зависимостей использование фабрики?

Я начинаю писать код, используя внедрение зависимостей. Теперь у меня есть несколько функций, написанных на DI, и мне нужен контейнер, чтобы сделать код более понятным (приложение находится в Symfony 1.4, поэтому я использую внешний DI-контейнер http://container.thephpleague.com/).

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

class TvMonitor
{
public function check(){ /* run check on every injected checker */ }
public function addChecker(CheckerInterface $checker){ ... }
public function addCheckers(CheckerInterface[] $chekers) { /* make foreach and use `addChecker` */ }
}

interface CheckerInterface
{
public function check();
public function getDetails(): array;
}

class CheckerFactory
{
public function getForFirstMonitor(): array
{
return [
new FileError('/some/file/path'),
new ApiBugs(new SomeApiClient('http://base_url/', 'api_key', new HttpClient()))
];
}

public function getForSecondMonitor(): array
{
return [
new FileError('/some/other/file/path'),
new OtherApiBugs(new SomeOtherApiClient())
];
}

}

В контроллерах код выглядит так:

/* first monitor controller */
$checker_factory = new CheckerFactory();

$monitor = new TvMonitor();
$monitor->addCheckers($checker_factory->getForFirstMonitor());

$monitor->check();/* second monitor controller */
$checker_factory = new CheckerFactory();

$monitor = new TvMonitor();
$monitor->addCheckers($checker_factory->getForSecondMonitor());

$monitor->check();

Теперь у меня есть 2 идеи. Одним из них является удаление фабрики и сохранение в контейнере 2 экземпляров TvMonitor с другим списком проверок:

$container
->add('fisrt_checker', FileError::class)
->withArgument('/some/file/path');
$container
->add('second_checker', ApiBugs::class)
->withArgument(...);

$container
->add('third_checker', FileError::class)
->withArgument('/some/other/file/path')
$container
->add('fourth_checker', OtherApiBugs::class)
->withArgument(...)

$container
->add('first_tv_monitor', TvMonitor::class)
->withMethodCall('addCheckers', ['first_checker', 'second_checker']);

$container
->add('second_tv_monitor', TvMonitor::class)
->withMethodCall('addCheckers', ['first_checker', 'fourth_checker']);

Контроллеры будут выглядеть так:

/* first monitor controller */
$monitor = $container->get('first_tv_monitor');

$monitor->check();/* second monitor controller */
$monitor = $container->get('second_tv_monitor');

$monitor->check();

Вторая идея состоит в том, чтобы внести некоторые изменения в фабрику (внедрить внутрь всего объекта, необходимого для создания контроллеров) и зарегистрировать его в контейнере:

class CheckerFactory
{
public function __contstruct(SomeApiClient $some_api_client, SomeOtherApiClient $some_other_api_client){ ... }
/* rest method are the same but use injected objects */
}

$container
->add('some_api_client', SomeApiClient::class);
$container
->add('some_other_api_client', SomeOtherApiClient::class);

$container
->add('checker_factory', CheckerFactory::class)
->withArgument('some_api_client')
->withArgument('some_other_api_client');

$container
->add('tv_monitor', TvMonitor::class);

Контроллеры будут выглядеть так:

/* first monitor controller */
$checker_factory = $container->get('checker_factory');

$monitor = $container->get('tv_monitor');
$monitor->addCheckers($checker_factory->getForFirstMonitor());

$monitor->check();/* second monitor controller */
$checker_factory = $container->get('checker_factory');

$monitor = $container->get('tv_monitor');
$monitor->addCheckers($checker_factory->getForSecondMonitor());

$monitor->check();

Я думаю, что первая идея не хороша, потому что контейнер (или, скорее, его конфигурация) делает слишком много.

Я предпочту вторую идею, потому что каждый элемент делает одно:

  • контейнер хранит единичные экземпляры
  • контроллер решает, какой пакет шашек будет использовать
  • Фабрика решает, какие шашки будут включены в каждую упаковку

Пожалуйста, дайте мне знать, что вы думаете об этих идеях (или, может быть, у вас есть другие). Я надеюсь, что кто-то с большим опытом в DI поможет мне с этим решением 🙂

2

Решение

Задача ещё не решена.

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

Других решений пока нет …

По вопросам рекламы [email protected]