Архитектура Android приложения. Слои, назначения, примеры использования v2

Архитектура Android приложения, основанная на принципах Clean Architecture или подобных им, обычно состоит из трех основных слоев: domain, data и ui. Каждый слой имеет свою ответственность и содержит определенные компоненты приложения.

  1. Domain Layer (Слой домена):
    • Этот слой содержит бизнес-логику и представляет основной функционал приложения.
    • Здесь определяются модели данных, интерфейсы репозиториев, интеракторы (use cases) и другие бизнес-компоненты.
    • Вся логика в этом слое должна быть независима от каких-либо конкретных реализаций или фреймворков.
// Модель данных (domain/entity)
data class User(val id: Int, val name: String, val email: String)

// Интерфейс репозитория (domain/repository)
interface UserRepository {
    suspend fun getUserById(userId: Int): User
}

// Интерактор (domain/usecase)
class GetUserByIdUseCase(private val userRepository: UserRepository) {
    suspend operator fun invoke(userId: Int): User {
        return userRepository.getUserById(userId)
    }
}
  1. Data Layer (Слой данных):
    • Этот слой содержит реализации репозиториев, работающие с данными из различных источников (например, базы данных, сети).
    • Здесь также могут находиться модели данных, специфичные для работы с определенными источниками данных.
    • Этот слой связывает бизнес-логику из слоя домена с реальными источниками данных.
// Реализация репозитория (data/repository)
class UserRepositoryImpl(private val apiService: ApiService) : UserRepository {
    override suspend fun getUserById(userId: Int): User {
        return apiService.getUserById(userId)
    }
}
  1. UI Layer (Пользовательский интерфейс):
    • Этот слой отвечает за отображение данных и взаимодействие с пользователем.
    • Здесь находятся Activity, Fragment, ViewModel и другие компоненты пользовательского интерфейса.
    • В этом слое происходит взаимодействие с бизнес-логикой через интеракторы (use cases) из слоя домена.
// ViewModel (ui/viewmodel)
class UserViewModel(private val getUserByIdUseCase: GetUserByIdUseCase) : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user

    fun fetchUser(userId: Int) {
        viewModelScope.launch {
            _user.value = getUserByIdUseCase(userId)
        }
    }
}

// Fragment (ui/view)
class UserDetailsFragment : Fragment() {
    private val viewModel: UserViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        viewModel.user.observe(viewLifecycleOwner, Observer { user ->
            // Обновление пользовательского интерфейса с данными пользователя
        })

        viewModel.fetchUser(userId)
    }
}

Такая архитектура позволяет разделить различные аспекты приложения и сделать его более модульным, легко тестируемым и поддающимся изменениям. Кроме того, она соблюдает принцип единственной ответственности (Single Responsibility Principle) и разделение интерфейсов (Interface Segregation Principle).