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

Для чего нужен UseCase в Clean Architecture?

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

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

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

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

Роль UseCase в Clean Architecture

UseCase (или Сценарий Использования, Interactor) — это центральный компонент доменного слоя (Domain Layer) в Clean Architecture. Его основное предназначение — инкапсулировать конкретную бизнес-логику, представляя собой атомарное правило или действие системы, которое имеет ценность для конечного пользователя или бизнеса.

Ключевые цели и назначение UseCase

  1. Изоляция бизнес-правил от фреймворков и инфраструктуры. UseCase не знает, является ли приложение Android, веб-сайтом или консольной утилитой. Он не зависит от Android SDK, библиотек UI, баз данных или сетевых клиентов. Это позволяет разрабатывать и тестировать логику в полной изоляции.

    // Пример: UseCase не должен содержать Android-зависимостей
    class GetUserProfileUseCase(
        private val userRepository: UserRepository // Доменный интерфейс, а не реализация
    ) {
        suspend operator fun invoke(userId: String): Result<User> {
            // Чистая бизнес-логика: проверка прав, преобразование данных
            return userRepository.getUserById(userId)
        }
    }
    
  2. Представление одной бизнес-транзакции. Каждый UseCase должен делать одну конкретную вещь. Например: LoginUserUseCase, FetchNewsUseCase, TransferFundsUseCase. Это соответствует принципу Single Responsibility и делает код читаемым, тестируемым и легко изменяемым.

  3. Определение четких точек входа и выхода. UseCase декларирует свои зависимости (репозитории, другие UseCase) через интерфейсы в доменном слое, а не через конкретные реализации. Результат своей работы он также возвращает в терминах доменных моделей или стандартных оберток (Result<T>, Either<Error, T>).

    // Четкий контракт: принимает параметры, возвращает Result
    class SearchProductsUseCase(
        private val productRepository: ProductRepository
    ) {
        suspend operator fun invoke(
            query: String,
            filters: Filters
        ): Result<List<Product>> { // Возвращает доменную модель Product
            if (query.isBlank()) {
                return Result.failure(ValidationError("Query is empty"))
            }
            return productRepository.search(query, filters)
        }
    }
    
  4. Координация потоков данных. UseCase управляет взаимодействием между сущностями (Entities) и репозиториями (Repository interfaces). Он определяет последовательность шагов: получить данные из одного источника, преобразовать их, применить правила, сохранить результат или запросить данные из другого источника.

Структура и практическое применение в Android

Типичный UseCase в Kotlin часто реализуется как класс с единственным публичным методом, часто через перегрузку оператора invoke(), что позволяет вызывать его как функцию.

// Доменный слой (module :domain)
class CalculateDiscountUseCase(
    private val customerRepository: CustomerRepository,
    private val discountRules: DiscountRules
) {
    suspend operator fun invoke(order: Order): MonetaryAmount {
        // 1. Получаем данные через интерфейс репозитория
        val customer = customerRepository.getCustomer(order.customerId)
        
        // 2. Применяем сложные бизнес-правила
        val loyaltyMultiplier = discountRules.getLoyaltyMultiplier(customer.yearsWithService)
        val seasonalDiscount = discountRules.getSeasonalDiscount(order.date)
        
        // 3. Выполняем расчет (ядро логики)
        val baseDiscount = order.total * 0.05
        val totalDiscount = baseDiscount * loyaltyMultiplier + seasonalDiscount
        
        // 4. Возвращаем результат в терминах домена
        return MonetaryAmount(totalDiscount.coerceAtLeast(0.0))
    }
}

// Интерфейс репозитория, который "живет" в доменном слое
interface CustomerRepository {
    suspend fun getCustomer(id: String): Customer
}

Преимущества использования UseCase

  • Повышение тестируемости: Логику можно покрыть юнит-тестами без необходимости эмулировать Android-окружение, используя моки репозиториев.
  • Упрощение чтения кода: Слой Presentation (ViewModel, Presenter) становится "тонким". Он лишь вызывает UseCase и управляет состоянием UI. Вся сложность сосредоточена в UseCase.
  • Гибкость и безопасность изменений: Изменения в работе с API или БД (инфраструктурный слой) не затрагивают бизнес-правила, если контракт репозитория (интерфейс) остается неизменным.
  • Четкое разделение ответственности: Разработчикам легче понять, где должна находиться новая логика. Вопросы "как показать?" решаются во ViewModel, вопросы "что сделать?" — в UseCase.
  • Подготовка к модульности: Доменный слой с UseCase легко выносится в отдельный Gradle-модуль, что ускоряет сборку и повышает переиспользуемость кода.

Вывод

UseCase в Clean Architecture — это не просто паттерн, а фундаментальная абстракция, которая защищает самое ценное в приложении — бизнес-логику. Он выступает в роли посредника между "сырыми" данными из внешнего мира и понятными для приложения бизнес-правилами, обеспечивая предсказуемость, устойчивость к изменениям во внешних слоях и создавая прочный фундамент для масштабируемой и поддерживаемой кодовой базы Android-приложения.