Какие знаешь сущности в Presentation слое Clean Architecture?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Сущности Presentation слоя в Clean Architecture
В Clean Architecture (Чистой Архитектуре) Presentation слой отвечает за отображение данных пользователю и обработку пользовательского ввода. Этот слой содержит несколько ключевых сущностей, которые обеспечивают разделение ответственности и тестируемость. Основные сущности:
1. View (Activity/Fragment/Composable)
View отвечает за отображение UI и передачу пользовательских событий в Presenter/ViewModel. В современных подходах View должна быть максимально "глупой" и содержать только логику, связанную с отрисовкой.
class ProductListFragment : Fragment() {
private val viewModel: ProductViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.state.observe(viewLifecycleOwner) { state ->
render(state) // Только отображение
}
binding.refreshButton.setOnClickListener {
viewModel.onRefreshClicked() // Передача событий
}
}
private fun render(state: ProductState) {
when (state) {
is ProductState.Loading -> showLoading()
is ProductState.Success -> showProducts(state.products)
is ProductState.Error -> showError(state.message)
}
}
}
2. Presenter/ViewModel
Presenter (в MVP) или ViewModel (в MVVM с Android Architecture Components) - это сущность, которая управляет состоянием View и обрабатывает бизнес-логику. Она получает данные из Domain слоя и преобразует их в формат, пригодный для отображения.
class ProductViewModel(
private val getProductsUseCase: GetProductsUseCase,
private val mapper: ProductMapper
) : ViewModel() {
private val _state = MutableStateFlow<ProductState>(ProductState.Loading)
val state: StateFlow<ProductState> = _state.asStateFlow()
init {
loadProducts()
}
fun onRefreshClicked() {
loadProducts()
}
private fun loadProducts() {
viewModelScope.launch {
_state.value = ProductState.Loading
try {
val products = getProductsUseCase.execute()
val uiModels = mapper.toUiModel(products)
_state.value = ProductState.Success(uiModels)
} catch (e: Exception) {
_state.value = ProductState.Error(e.message ?: "Unknown error")
}
}
}
}
3. UI Models
UI Models (или View Models, Presentation Models) - это специализированные классы данных, оптимизированные для отображения в UI. Они отличаются от Domain Models и содержат только те поля, которые необходимы для отрисовки.
data class ProductUiModel(
val id: String,
val displayName: String,
val formattedPrice: String,
val isInStock: Boolean,
val imageUrl: String,
val rating: Float,
val showDiscountBadge: Boolean,
val discountText: String? = null
)
// Маппер для преобразования Domain Model в UI Model
class ProductMapper @Inject constructor(
private val currencyFormatter: CurrencyFormatter,
private val resourceProvider: ResourceProvider
) {
fun toUiModel(domainProduct: Product): ProductUiModel {
return ProductUiModel(
id = domainProduct.id,
displayName = domainProduct.name.toDisplayName(),
formattedPrice = currencyFormatter.format(domainProduct.price),
isInStock = domainProduct.quantity > 0,
imageUrl = domainProduct.images.firstOrNull() ?: "",
rating = domainProduct.rating,
showDiscountBadge = domainProduct.discount > 0,
discountText = if (domainProduct.discount > 0) {
"-${domainProduct.discount}%"
} else null
)
}
}
4. State Management
State Management сущности представляют различные состояния UI. Это обычно sealed классы или интерфейсы, которые инкапсулируют все возможные состояния экрана.
sealed class ProductState {
object Loading : ProductState()
data class Success(val products: List<ProductUiModel>) : ProductState()
data class Error(val message: String) : ProductState()
object Empty : ProductState()
}
5. Contract/Interface
Contract определяет взаимодействие между View и Presenter/ViewModel. Это особенно важно в подходе MVP для обеспечения тестируемости.
// Контракт для MVP подхода
interface ProductContract {
interface View {
fun showLoading()
fun hideLoading()
fun showProducts(products: List<ProductUiModel>)
fun showError(message: String)
fun showEmptyState()
}
interface Presenter {
fun attachView(view: View)
fun detachView()
fun loadProducts()
fun onProductClicked(productId: String)
fun onRefresh()
}
}
6. UI Components и Custom Views
Специализированные UI Components и Custom Views, которые инкапсулируют сложное поведение отображения.
7. Navigation Components
Navigation Components отвечают за переходы между экранами. В современных приложениях это может быть Jetpack Navigation Component или кастомная реализация навигации.
8. Adapters и ViewHolders
Для RecyclerView и других адаптеров списков используются Adapters и ViewHolders, которые также являются частью Presentation слоя.
Ключевые принципы Presentation слоя:
- Пассивность View: View только отображает данные и передает события
- Тестируемость: Бизнес-логика в Presenter/ViewModel легко тестируется без Android зависимостей
- Однонаправленный поток данных: Данные текут в одном направлении (Domain → Presentation → View)
- Отсутствие Domain логики: Presentation слой не должен содержать бизнес-правил
- Реактивность: Использование LiveData, StateFlow, RxJava для реактивного обновления UI
Этот подход обеспечивает разделение ответственности, легкое тестирование и поддержку кода, позволяя заменять компоненты (например, менять фреймворки UI) без влияния на бизнес-логику приложения.