В чем разница между Use Case и Interactor в Clean Architecture?

«В чем разница между Use Case и Interactor в Clean Architecture?» — вопрос из категории Архитектура, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Clean Architecture (и таких её вариантах, как VIPER) Use Case и Interactor — это тесно связанные, но концептуально разные компоненты.

Определения:

  • Use Case (Сценарий использования) — это бизнес-правило или требование. Он описывает ЧТО должна сделать система (например, "получить список новостей", "создать заказ"). Use Case — это абстракция, часто представленная в виде протокола/интерфейса.
  • Interactor (Интерактор) — это конкретный исполнитель бизнес-логики. Он реализует один или несколько Use Cases, координируя работу сущностей (Entities) и внешних зависимостей (например, репозиториев). Он описывает КАК выполнить задачу.

Аналогия:

Use Case — это чертёж или техническое задание ("построить дом").
Interactor — это прораб, который организует процесс, нанимает строителей (репозитории) и следит за выполнением работ по этому чертежу.

Пример кода:

1. Use Case (протокол, определяющий контракт):

// Описывает ЧТО нужно сделать. Не зависит от фреймворков (UIKit, Core Data).
protocol FetchUserProfileUseCase {
    func execute(userId: String) async throws -> UserProfile
}

2. Interactor (конкретная реализация Use Case):

// Реализует КАК это сделать. Содержит бизнес-логику.
class FetchUserProfileInteractor: FetchUserProfileUseCase {
    // Зависимости инжектируются (репозиторий, сервис)
    private let userRepository: UserRepositoryProtocol
    private let analyticsService: AnalyticsServiceProtocol

    init(userRepository: UserRepositoryProtocol, analyticsService: AnalyticsServiceProtocol) {
        self.userRepository = userRepository
        self.analyticsService = analyticsService
    }

    func execute(userId: String) async throws -> UserProfile {
        // 1. Координация бизнес-логики
        let user = try await userRepository.fetchUser(by: userId)

        // 2. Дополнительные правила (например, кэширование, логирование)
        analyticsService.trackEvent("user_profile_fetched", userId: userId)

        // 3. Преобразование данных для возврата
        return UserProfile(from: user)
    }
}

Ключевое отличие:

  • Use Case — это декларация намерения (интерфейс). Он принадлежит слою бизнес-правил.
  • Interactor — это реализация этого намерения с конкретной логикой и зависимостями. Он служит мостом между бизнес-правилами (Use Case) и слоем данных (репозитории).

Такое разделение делает код тестируемым (Use Case можно замокать) и позволяет менять реализацию (Interactor), не меняя объявленный контракт.