Ответ
Проблема: Передача большого числа сервисов (Network, Database, Analytics) через init приводит к раздуванию конструктора и сложности тестирования.
Решение — паттерны управления зависимостями:
-
Контейнер внедрения зависимостей (DI Container):
- Принцип: Централизованный реестр создает и предоставляет зависимости.
-
Пример с Swinject:
let container = Container() container.register(NetworkService.self) { _ in NetworkServiceImpl() } container.register(DatabaseService.self) { _ in DatabaseServiceImpl() } class ViewModel { let network: NetworkService let database: DatabaseService init(resolver: Resolver) { self.network = resolver.resolve(NetworkService.self)! self.database = resolver.resolve(DatabaseService.self)! } }
-
Локатор служб (Service Locator):
- Принцип: Глобальный или контекстный объект, который возвращает требуемые сервисы по запросу.
-
Пример:
class ServiceLocator { static let shared = ServiceLocator() private var services: [String: Any] = [:] func register<T>(_ service: T) { services["(T.self)"] = service } func resolve<T>() -> T? { return services["(T.self)"] as? T } }
-
@EnvironmentObject(SwiftUI):- Принцип: Объект, внедренный в иерархию представлений и доступный всем дочерним view.
-
Пример:
class AppDependencies: ObservableObject { /* сервисы */ } // В корневом View ContentView().environmentObject(AppDependencies()) // В дочернем View struct ChildView: View { @EnvironmentObject var deps: AppDependencies }
Рекомендация: DI Container предпочтительнее для сложных проектов, так как он делает зависимости явными и облегчает модульное тестирование. Service Locator считается антипаттерном в некоторых случаях, так как скрывает зависимости.