Назад к задачамПолучайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Middle — Senior
8
Улучшение структуры кода: вариант 1
Условие задачи
Необходимо провести рефакторинг представленного кода, повысив его читаемость, тестируемость и отделив бизнес‑логику от UI‑слоя. При этом следует обратить внимание на корректное использование корутин, Flow и Rx‑компонентов, а также на правильное управление ресурсами в ViewModel.
class ScreenViewModel(
val configs: ConfigRepository,
val holder: UserHolder,
val cards: CardRepository,
val analytics: AnalyticsService,
val context: Context
) : ViewModel() {
lateinit var config: Config
lateinit var card: CardType
var liveData = MutableLiveData<UiModel>()
var successfulChecks = 0L
init {
GlobalScope.launch {
flowOf(configs.loadConfig())
.zip(cards.observeAvailableCard(), { it1, it2 -> Pair(it1, it2) })
.flowOn(Dispatchers.Default)
.filter {
it.second == CardType.PREMIUM && holder.getUserScore() > 42 ||
it.second != CardType.PREMIUM &&
it.first.specialUsers.contains(holder.getUserId())
}
.onEach {
config = it.first
card = it.second
}
.flatMapConcat {
flowOf(configs.checkBlackList(it.second, holder.getUserId()))
.apply { successfulChecks++ }
}
.collect {
liveData.value = UiModel(
title = when {
card == CardType.CREDIT -> config.creditTitle
card == CardType.DEBIT -> config.debitTitle
card == CardType.KID -> config.kidTitle
card == CardType.PREMIUM -> context.getString(R.string.congratulations)
else -> ""
},
description = context.getString(
R.string.description_pattern,
config.kinderSurprizeCashback
)
)
}
}
}
var disposables: CompositeDisposable? = CompositeDisposable()
override fun onCleared() {
GlobalScope.launch {
analytics.sendSuccessfulChecks(successfulChecks)
}
super.onCleared()
}
}
interface Config {
val debitTitle: String
val creditTitle: String
val kidTitle: String
val kinderSurprizeCashback: Long
val specialUsers: List<Long>
}
interface ConfigRepository {
suspend fun loadConfig(): Config
fun checkBlackList(cardType: CardType, userId: Long): BlackList
}
interface BlackList {
var successfulChecks: Long
}
interface CardRepository {
fun observeAvailableCard(): Flow<CardType>
}
interface UserHolder {
fun getUserId(): Long
fun getUserScore(): Long
}
interface AnalyticsService {
@FormUrlEncoded
@POST("/analytics")
suspend fun sendSuccessfulChecks(count: Long)
}
enum class CardType { DEBIT, CREDIT, KID, PREMIUM }
class UiModel(val title: String, val description: String)