За последние несколько дней я много читал о внедрении зависимостей и использовал Aura.DI, чтобы поиграть с принципами IoC. Я столкнулся с несколькими проблемами, которые, как я слышал, часто встречаются при реализации этого шаблона, но я все еще не совсем уверен в некоторых деталях.
Если я хочу внедрить регистратор (скажем, Monolog) в класс контроллера (простой пример), я бы хотел использовать имя класса в качестве канала регистрации (в основном new Logger('somecontroller')
), насколько я могу судить, это будет означать ручное определение этой «инъекции» для каждого класса, прав ли я в этом?
Это:
$controller = new PageController(new Logger('PageController'));
в Aura.DI, будет:
$di->params['PageController'] = [
'logger' => $di->lazyNew('Logger', ['name' => 'PageController'])
];
но я должен сделать это для каждый контроллер, для которого я хочу другой канал регистрации ?! Я слышал, что вы можете использовать здесь абстрактный шаблон фабрики, но я не уверен, как это будет работать? (Я понимаю шаблон «Фабрика», но никогда не думал, что он мне поможет. Хотя шаблон «Абстрактная фабрика» является новым для меня)
Я знаю, что мог бы написать простой метод для перебора массива контроллеров и сделать это менее многословным способом, но было бы неправильно делать это.
Я тоже сталкивался этот пост на Reddit и думал, что это имеет смысл. Если мне все равно придется вручную настраивать все эти зависимости, почему бы просто не сделать мою конфигурацию реальной реализацией? Может быть, это развалится, когда дерево зависимостей станет немного больше? Я подумал, что стоит спросить, что думают люди.
РЕДАКТИРОВАТЬ: Просто издевались над примером о том, как подход «сделай сам» может работать, и, кажется, все в порядке… мысли? (вероятно, многие из этих методов должны быть приватными, но вы получите представление).
Любой свет, который вы можете пролить на любой / все мои вопросы, будет оценен.
Вы можете сделать это несколькими разными способами.
Внедрить LoggerFactory
класс к PageController
,
class PageController
{
public function __construct(LoggerFactory $loggerFactory)
{
$this->loggerFactory = $loggerFactory;
}
public function someAction()
{
$this->loggerFactory->newInstance(__CLASS__);
}
}
class LoggerFactory
{
public function newInstance($name)
{
return new Logger($name);
}
}
С помощью withName () того же самого Logger
, Может быть, это проще. Вы вводите логгер и звоните $newlogger = $this->logger->withName(__CLASS__);
и получить клонированный новый экземпляр.
С использованием Фабрики экземпляров
Вот ExampleNeedsFactory
является PageController
, ExampleStruct
является Logger
$di->params['PageController']['loggerFactory'] = $di->newFactory('Logger');
class PageController
{
public function __construct(LoggerFactory $loggerFactory)
{
$this->loggerFactory = $loggerFactory;
}
public function someAction()
{
$logger = $this->getLogger();
}
public function getLogger()
{
$this->loggerFactory->__invoke(__CLASS__);
}
}
Примечание: в этом случае getLogger
всегда возвращает новый регистратор. Если вам нужен тот же экземпляр, установите регистратор.
public function getLogger()
{
if (! $this->logger) {
$this->logger = $this->loggerFactory->__invoke(__CLASS__);
}
return $this->logger;
}
Вы также можете переместить эти методы в AbstractController
класс, так что вам не нужно каждый раз писать то, что вам нужно ввести в контроллер. (@camel_case упоминал об этом в своих комментариях)
Есть также функция автоматического разрешения для Aura.Di, которая помогает не писать много настроек.
Надеюсь, это поможет!
Других решений пока нет …