В первом издании говорится (глава 3, стр. 82):
В чистом виде шаблон Register Resolve Release гласит, что вы должны делать только одиночный вызов метода на каждом этапе [...], приложение должно содержать только single вызов метода Resolve
.
Это описание основано на идее, что ваше приложение содержит только один корневой объект (обычно при написании простого консольного приложения) или одну логическую группу корневых типов, например, Контроллеры MVC. Например, с контроллерами MVC у вас будет пользовательская фабрика контроллеров, которая предоставляется платформой MVC с типом контроллера для сборки. В этом случае эта фабрика будет иметь только один вызов Resolve
при предоставлении типа.
Однако существуют случаи, когда в вашем приложении есть несколько групп корневых типов. Например, веб-приложение может иметь сочетание контроллеров API, контроллеров MVC и компонентов просмотра. Для каждой логической группы в вашем приложении, вероятно, будет один вызов Resolve
и, следовательно, несколько вызовов Resolve
(обычно потому, что каждый корневой тип получает свою собственную фабрику) в вашем приложении.
Существуют и другие веские причины для обратного вызова в контейнер. Например, вы можете отложить построение части графа объектов для борьбы с проблемой зависимостей . Это похоже на ваш случай. Еще одна причина для дополнительного разрешения - использование шаблона Mediator для отправки сообщений определенной реализации (или реализациям), которые могут обработать это сообщение. В этом случае ваша реализация Mediator обычно оборачивает контейнер и вызывает Resolve
. Абстракция Посредника, скорее всего, будет определена в библиотеке вашего домена, в то время как реализация Посредника с ее знанием контейнера должна быть определена внутри Корня композиции.
Таким образом, рекомендация о единственном вызове Resolve
не должна восприниматься буквально. Реальная цель здесь - построить как можно больше графов объектов за один вызов, по сравнению с тем, чтобы позволить самим классам перезванивать в контейнер для разрешения своих зависимостей (то есть анти-паттерна Service Locator).
Другой важный момент, который ( второе издание из) книги делает
Запрос на зависимости, даже если через DI-контейнер, становится неправильным при поиске службы. Когда код приложения (в отличие от кода инфраструктуры) активно запрашивает службу, чтобы получить необходимые зависимости, он становится локатором службы.
Контейнер DI, инкапсулированный в корне композиции, не является локатором службы - это компонент инфраструктуры.
(примечание: эта цитата взята из второго издания ; хотя первое издание также содержит эту информацию, она может быть сформулирована по-другому).
Таким образом, цель паттерна RRR состоит в том, чтобы способствовать инкапсуляции DI-контейнера в корне композиции, поэтому он настаивает на единственном вызове Resolve
.
Обратите внимание, что во время написания второго издания мы с Марком хотели переписать обсуждение шаблона RRR. Основной причиной этого было то, что мы обнаружили, что текст сбивает с толку (как показывает ваш вопрос). Однако, в конце концов, у нас закончилось время, поэтому мы решили просто удалить эту сложную дискуссию. Мы чувствовали, что самые важные моменты уже были сделаны.