Ответ
Router (или Assembly/Builder) получает зависимости для сборки модуля из внешнего DI-контейнера (Dependency Injection Container) или фабрики зависимостей. Он не создает зависимости сам, а лишь запрашивает их.
Основные подходы:
-
Использование DI-контейнера (Swinject, Dip): Контейнер предварительно регистрирует все сервисы (сетевые, хранилища, аналитики). Router разрешает (resolve) зависимости из контейнера при сборке модуля.
// Где-то при запуске приложения container.register(NetworkService.self) { _ in NetworkServiceImpl() } container.register(DataStorage.self) { _ in CoreDataStorage() } // В роутере class ProfileRouter { let container: Container // Контейнер внедряется в роутер func createModule() -> UIViewController { let view = ProfileViewController() // Резолвим ViewModel со всеми ее зависимостями из контейнера let viewModel = container.resolve(ProfileViewModel.self)! view.viewModel = viewModel return view } } -
Явная передача через инициализатор (Manual Dependency Injection): Зависимости передаются в роутер извне (например, из родительского модуля или координатора), а роутер передает их дальше во ViewModel/Presenter.
class ProfileRouter { let service: NetworkService let storage: DataStorage init(service: NetworkService, storage: DataStorage) { self.service = service self.storage = storage } func createModule() -> UIViewController { let view = ProfileViewController() // Создаем ViewModel, передавая зависимости явно let viewModel = ProfileViewModel(service: service, storage: storage) view.viewModel = viewModel return view } }
Ключевая идея: Router выступает как компоновщик (assembler) модуля. Он знает, какие компоненты (View, ViewModel, Presenter) и какие зависимости нужны для их работы, но сами зависимости предоставляются извне, что обеспечивает тестируемость и соблюдение принципа инверсии зависимостей (DIP).