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

Что такое interactor?

1.0 Junior🔥 112 комментариев
#Архитектура Flutter

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

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

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

Interactor в архитектуре Clean Architecture

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

Слои Clean Architecture

┌─────────────────────────────┐
│      Presentation (UI)      │
├─────────────────────────────┤
│   Interactor (Use Case)     │  <- Именно здесь
├─────────────────────────────┤
│ Repository (Data Access)    │
├─────────────────────────────┤
│  Entity (Domain Models)     │
└─────────────────────────────┘

Interactor — это связующее звено между UI и данными.

Структура Interactor

Interactor содержит:

  • Входные данные (Input)
  • Выходные данные (Output)
  • Логику выполнения
// Определяем контракт (interface)
abstract class GetUserInteractor {
  Future<void> call(GetUserInput input);
}

// Input — что нужно получить
class GetUserInput {
  final String userId;
  GetUserInput({required this.userId});
}

// Output — результат (обычно через callback)
abstract class GetUserOutput {
  void onSuccess(User user);
  void onError(Failure failure);
}

// Реализация Interactor
class GetUserUseCaseImpl implements GetUserInteractor {
  final UserRepository repository;

  GetUserUseCaseImpl({required this.repository});

  @override
  Future<void> call(GetUserInput input) async {
    try {
      // Бизнес-логика: получаем пользователя из репозитория
      final user = await repository.getUserById(input.userId);
      
      // Валидация в Interactor
      if (user.age < 18) {
        return;
      }
      
      // Возвращаем результат через presenter
      // (presentation слой обрабатывает результат)
    } on Exception catch (e) {
      // Обработка ошибок
      return;
    }
  }
}

Практический пример: Аутентификация

// Entity — доменная модель
class User {
  final String id;
  final String email;
  final String name;

  User({
    required this.id,
    required this.email,
    required this.name,
  });
}

// Input для interactor
class LoginInput {
  final String email;
  final String password;

  LoginInput({
    required this.email,
    required this.password,
  });
}

// Output для presenter
abstract class LoginOutput {
  void onSuccess(User user);
  void onEmailError(String message);
  void onPasswordError(String message);
  void onServerError(String message);
}

// Interactor (Use Case)
class LoginUseCaseImpl implements LoginUseCase {
  final AuthRepository authRepository;
  final UserRepository userRepository;

  LoginUseCaseImpl({
    required this.authRepository,
    required this.userRepository,
  });

  @override
  Future<void> call(
    LoginInput input,
    LoginOutput presenter,
  ) async {
    // Валидация email
    if (!_isValidEmail(input.email)) {
      presenter.onEmailError('Invalid email format');
      return;
    }

    // Валидация пароля
    if (input.password.length < 6) {
      presenter.onPasswordError('Password must be at least 6 characters');
      return;
    }

    try {
      // Бизнес-логика: аутентификация
      final token = await authRepository.authenticate(
        input.email,
        input.password,
      );

      // Получаем данные пользователя
      final user = await userRepository.getUser(token);

      // Возвращаем результат
      presenter.onSuccess(user);
    } on ServerException catch (e) {
      presenter.onServerError(e.message);
    } on NetworkException catch (e) {
      presenter.onServerError('Network error: check your connection');
    }
  }

  bool _isValidEmail(String email) {
    return email.contains('@');
  }
}

Использование Interactor в Presenter/BLoC

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final LoginUseCase loginUseCase;

  LoginBloc({required this.loginUseCase})
      : super(const LoginState.initial()) {
    on<LoginButtonPressed>(_onLoginButtonPressed);
  }

  Future<void> _onLoginButtonPressed(
    LoginButtonPressed event,
    Emitter<LoginState> emit,
  ) async {
    emit(const LoginState.loading());

    await loginUseCase.call(
      LoginInput(email: event.email, password: event.password),
      _LoginPresenter(emit),
    );
  }
}

// Presenter реализует Output
class _LoginPresenter extends LoginOutput {
  final Emitter<LoginState> emit;

  _LoginPresenter(this.emit);

  @override
  void onSuccess(User user) {
    emit(LoginState.success(user));
  }

  @override
  void onEmailError(String message) {
    emit(LoginState.emailError(message));
  }

  @override
  void onPasswordError(String message) {
    emit(LoginState.passwordError(message));
  }

  @override
  void onServerError(String message) {
    emit(LoginState.serverError(message));
  }
}

Преимущества Interactor

  • Независимость — бизнес-логика не зависит от UI или БД
  • Тестируемость — легко написать unit-тесты
  • Переиспользование — один Interactor для разных UI (BLoC, Riverpod, GetX)
  • Чистота — разделение ответственности
  • Масштабируемость — легко добавлять новые сценарии

Interactor — это сердце приложения, где живёт вся полезная бизнес-логика.

Что такое interactor? | PrepBro