← Назад к вопросам

Какая ответственность у Router?

2.2 Middle🔥 171 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответственность Router в iOS-архитектуре

Router (или Router) — это ключевой компонент в архитектурных паттернах VIPER и Clean Swift, отвечающий за навигацию между модулями и инкапсуляцию логики переходов. Его основная цель — отделить навигационную логику от бизнес-логики и представления, следуя принципу единой ответственности (Single Responsibility Principle).

Основные обязанности Router

  1. Управление навигацией между модулями

    • Осуществляет переходы между экранами (push, present, dismiss, pop).
    • Обрабатывает глубокие ссылки (deeplinks) и универсальные ссылки (universal links).
    • Управляет навигационными стеками (UINavigationController, UITabBarController).
  2. Инкапсуляция зависимостей модулей

    • Собирает все компоненты модуля (View, Interactor, Presenter, Entity) и устанавливает связи между ними.
    • Внедряет зависимости, используя фабрики или сборщики (Assemblers).
  3. Передача данных между модулями

    • Передаёт параметры при переходах (например, идентификаторы объектов).
    • Реализует делегатные протоколы для обратной связи между модулями.
  4. Управление жизненным циклом модулей

    • Создаёт и освобождает модули, когда они больше не нужны.
    • Управляет зависимостями, связанными с памятью.

Пример кода 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 решает эти проблемы, вынося навигацию в отдельный компонент с чётко определённым контрактом.

Практические рекомендации

  1. Используйте протоколы для определения интерфейсов Router:
protocol AppRouterProtocol {
    func showLogin()
    func showMainFlow()
    func handleDeeplink(_ url: URL)
}
  1. Внедряйте зависимости через инициализатор, а не синглтоны.

  2. Разделяйте ответственность: Создайте отдельный Coordinator для управления потоками приложения, если навигация становится сложной.

Router — это мост между модулями, который превращает жёстко связанные переходы в декларативные, тестируемые и поддерживаемые потоки данных. Его правильная реализация значительно упрощает масштабирование приложения и снижает связанность компонентов системы.