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

В чем разница между Presenter и Interactor?

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

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

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

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

Разница между Presenter и Interactor в архитектуре VIPER/Clean Swift

В архитектурах VIPER и Clean Swift (VIP), которые следуют принципам Clean Architecture, Presenter и Interactor играют фундаментально разные роли, хотя оба являются посредниками между пользовательским интерфейсом и бизнес-логикой. Их различие — краеугольный камень разделения ответственности.

Основное назначение и ответственность

Interactor (Интерактор)

Это ядро бизнес-логики приложения. Его главная задача — выполнение конкретных юзкейсов (Use Cases). Interactor:

  • Работает с сущностями (Entities) — чистыми моделями данных, не зависящими от фреймворков.
  • Содержит бизнес-правила и логику обработки данных (валидация, вычисления, фильтрация).
  • Не знает о существовании пользовательского интерфейса (UI). Он абстрагирован от UIKit/SwiftUI.
  • Получает сырые или подготовленные данные от Gateways (например, NetworkService, DatabaseService) через протоколы.
  • Результат своей работы передает Presenter в формате, удобном для бизнес-логики (обычно те же Entities или простые структуры).

Presenter (Презентер)

Это подготовщик данных для отображения. Его главная задача — преобразовывать данные из бизнес-моделей (от Interactor) в модели представления (View Models), понятные View.

  • Работает с моделями представления (View Models) — структурами, оптимизированными для отображения (например, отформатированные строки дат, флаги для скрытия/показа UI-элементов).
  • Содержит логику подготовки данных для UI, но не саму бизнес-логику.
  • Знает о View, но общается с ней через протокол, что позволяет легко подменять реализацию (например, для тестов).
  • Решает, что и как показать пользователю: "показать ошибку", "обновить список", "перейти к следующему экрану".

Сравнение на примере VIPER

Рассмотрим сценарий "Загрузка списка новостей".

// Entity: Чистая бизнес-модель
struct Article {
    let id: Int
    let title: String
    let publicationDate: Date
    let isRead: Bool
}

// View Model: Модель, готовящаяся для отображения
struct ArticleViewModel {
    let title: String
    let subtitle: String // "Опубликовано: 15 мая 2023"
    let isHighlighted: Bool
}

Работа Interactor:

protocol ArticlesInteractorInput: AnyObject {
    func fetchArticles()
}

protocol ArticlesInteractorOutput: AnyObject {
    func didFetchArticles(_ articles: [Article])
    func didFailToFetchArticles(with error: Error)
}

final class ArticlesInteractor: ArticlesInteractorInput {
    weak var presenter: ArticlesInteractorOutput?
    let service: ArticlesServiceProtocol // Протокол для абстракции над сетью/БД

    func fetchArticles() {
        service.loadArticles { [weak self] result in
            switch result {
            case .success(let articles):
                // Бизнес-логика: например, помечаем статьи старше недели как прочитанные
                let processedArticles = self?.applyBusinessRules(to: articles) ?? articles
                self?.presenter?.didFetchArticles(processedArticles)
            case .failure(let error):
                self?.presenter?.didFailToFetchArticles(with: error)
            }
        }
    }

    private func applyBusinessRules(to articles: [Article]) -> [Article] {
        let weekAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date())!
        return articles.map { article in
            var modifiedArticle = article
            if article.publicationDate < weekAgo {
                modifiedArticle.isRead = true
            }
            return modifiedArticle
        }
    }
}

Работа Presenter:

protocol ArticlesViewInput: AnyObject {
    func showArticles(_ viewModels: [ArticleViewModel])
    func showError(message: String)
}

final class ArticlesPresenter: ArticlesInteractorOutput {
    weak var view: ArticlesViewInput?
    let dateFormatter: DateFormatter

    init() {
        dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .long
        dateFormatter.timeStyle = .none
    }

    // Interactor передал бизнес-модели (Entities)
    func didFetchArticles(_ articles: [Article]) {
        // Преобразуем Entity во View Model: это ответственность Presenter
        let viewModels = articles.map { article in
            ArticleViewModel(
                title: article.title,
                subtitle: "Опубликовано: \(dateFormatter.string(from: article.publicationDate))",
                isHighlighted: !article.isRead // Логика отображения на основе бизнес-состояния
            )
        }
        view?.showArticles(viewModels)
    }

    func didFailToFetchArticles(with error: Error) {
        // Подготавливаем сообщение об ошибке для пользователя
        let userMessage = "Не удалось загрузить новости. Пожалуйста, проверьте соединение."
        view?.showError(message: userMessage)
    }
}

Ключевые различия в виде таблицы

КритерийInteractorPresenter
Основная рольИсполнитель бизнес-юзкейсов.Преобразователь данных для UI.
Работает сEntities (бизнес-модели), Protocols (для сервисов).View Models, Entities (на вход), View Protocol (на выход).
ОтветственностьВалидация, вычисления, применение бизнес-правил, работа с данными.Форматирование, подготовка строк, определение состояния UI-элементов.
Знание о UIНет (полная абстракция).Да (знает, что нужно показать, но не как это рендерить).
ЗависимостиСервисы (сеть, БД), другие Interactors.Форматтеры, мапперы, Router (для навигации).
ТестируемостьЛегко тестируется юнит-тестами, так как не зависит от фреймворков.Легко тестируется юнит-тестами с моком View.

Важный принцип взаимодействия

Поток данных обычно следует паттерну: View -> Presenter -> Interactor -> Presenter -> View

  1. View (например, ViewController) сообщает Presenter о действии пользователя (например, viewDidLoad).
  2. Presenter запрашивает у Interactor выполнение бизнес-логики (например, fetchArticles).
  3. Interactor выполняет работу, получая данные из сервисов, применяя правила.
  4. Interactor возвращает результат (Entities) Presenter.
  5. Presenter преобразует Entities в View Models и передает их View для отображения.

Итог: Interactor — это "мозг" бизнес-логики, независимый от платформы. Presenter — это "переводчик", который адаптирует результаты работы "мозга" для "лица" приложения (View). Их четкое разделение позволяет создавать гибкий, тестируемый и поддерживаемый код, где изменения в UI не затрагивают бизнес-правила, и наоборот.

В чем разница между Presenter и Interactor? | PrepBro