Какая ответственность у Router?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответственность Router в iOS-архитектуре
Router (или Router) — это ключевой компонент в архитектурных паттернах VIPER и Clean Swift, отвечающий за навигацию между модулями и инкапсуляцию логики переходов. Его основная цель — отделить навигационную логику от бизнес-логики и представления, следуя принципу единой ответственности (Single Responsibility Principle).
Основные обязанности Router
-
Управление навигацией между модулями
- Осуществляет переходы между экранами (push, present, dismiss, pop).
- Обрабатывает глубокие ссылки (deeplinks) и универсальные ссылки (universal links).
- Управляет навигационными стеками (UINavigationController, UITabBarController).
-
Инкапсуляция зависимостей модулей
- Собирает все компоненты модуля (View, Interactor, Presenter, Entity) и устанавливает связи между ними.
- Внедряет зависимости, используя фабрики или сборщики (Assemblers).
-
Передача данных между модулями
- Передаёт параметры при переходах (например, идентификаторы объектов).
- Реализует делегатные протоколы для обратной связи между модулями.
-
Управление жизненным циклом модулей
- Создаёт и освобождает модули, когда они больше не нужны.
- Управляет зависимостями, связанными с памятью.
Пример кода Router в VIPER
import UIKit
protocol ProductListRouterProtocol: AnyObject {
func navigateToProductDetail(with productID: String)
func navigateToCart()
}
final class ProductListRouter: ProductListRouterProtocol {
weak var viewController: UIViewController?
private let factory: ModuleFactoryProtocol
init(factory: ModuleFactoryProtocol) {
self.factory = factory
}
func navigateToProductDetail(with productID: String) {
// Создаём модуль деталей продукта через фабрику
let detailModule = factory.makeProductDetailModule(productID: productID)
// Осуществляем переход
viewController?.navigationController?.pushViewController(
detailModule.viewController,
animated: true
)
}
func navigateToCart() {
let cartModule = factory.makeCartModule()
// Используем модальный переход
viewController?.present(
cartModule.viewController,
animated: true,
completion: nil
)
}
}
Преимущества использования Router
- Тестируемость: Навигационную логику можно тестировать изолированно, без создания реальных UIViewControllers.
- Гибкость: Изменение навигационных потоков не затрагивает бизнес-логику.
- Повторное использование: Модули становятся независимыми от конкретного навигационного контекста.
- Чистая архитектура: Соответствует принципам Clean Architecture, где навигация — это деталь реализации.
Сравнение с другими паттернами
В MVC и MVVM навигация часто реализуется во ViewController/ViewModel, что приводит к:
- Перегруженным контроллерам
- Смешиванию ответственности
- Сложностям в тестировании
Router решает эти проблемы, вынося навигацию в отдельный компонент с чётко определённым контрактом.
Практические рекомендации
- Используйте протоколы для определения интерфейсов Router:
protocol AppRouterProtocol {
func showLogin()
func showMainFlow()
func handleDeeplink(_ url: URL)
}
-
Внедряйте зависимости через инициализатор, а не синглтоны.
-
Разделяйте ответственность: Создайте отдельный Coordinator для управления потоками приложения, если навигация становится сложной.
Router — это мост между модулями, который превращает жёстко связанные переходы в декларативные, тестируемые и поддерживаемые потоки данных. Его правильная реализация значительно упрощает масштабирование приложения и снижает связанность компонентов системы.