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

Как делал маппинг данных между слоями архитектуры

1.0 Junior🔥 141 комментариев
#Архитектура и паттерны#Опыт и софт-скиллы

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

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

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

Маппинг данных между слоями в Android-архитектуре

Маппинг данных — это процесс преобразования объектов данных при их передаче между слоями архитектуры (например, из сетевого слоя в слой домена, а затем в UI-слой). Я придерживаюсь принципа разделения ответственности: каждый слой работает со своими собственными моделями данных, что обеспечивает гибкость, тестируемость и соблюдение принципа единой ответственности.

Основные типы моделей данных

В типичной чистой архитектуре (Clean Architecture) или MVVM я использую следующие модели:

  1. Data Model (DTO/Entity) — модели для работы с сетью и базой данных.
  2. Domain Model — бизнес-объекты, независимые от фреймворков.
  3. UI Model (ViewState/ViewEntity) — данные, оптимизированные для отображения.

Пример структур:

// Data Layer
data class UserDto(
    @SerializedName("id")
    val id: Long,
    @SerializedName("full_name")
    val fullName: String,
    @SerializedName("email_address")
    val email: String
)

// Domain Layer
data class User(
    val id: Long,
    val name: String,
    val email: String
)

// UI Layer
data class UserUi(
    val id: String,
    val displayName: String,
    val email: String,
    val avatarColor: Int
)

Способы реализации маппинга

Я использую несколько подходов в зависимости от сложности проекта:

1. Ручной маппинг в мапперах

Создаю отдельные классы-мапперы с статическими методами или функциями расширения:

class UserMapper {
    fun toDomain(dto: UserDto): User {
        return User(
            id = dto.id,
            name = dto.fullName,
            email = dto.email
        )
    }
    
    fun toUi(domain: User): UserUi {
        return UserUi(
            id = domain.id.toString(),
            displayName = formatName(domain.name),
            email = domain.email,
            avatarColor = generateColor(domain.id)
        )
    }
    
    private fun formatName(name: String): String {
        return name.trim().split(" ").joinToString(" ") { it.capitalize() }
    }
}

2. Использование функций расширения

Более идиоматичный Kotlin-подход:

fun UserDto.toDomain(): User = User(
    id = this.id,
    name = this.fullName,
    email = this.email
)

fun User.toUi(): UserUi = UserUi(
    id = this.id.toString(),
    displayName = this.name.toTitleCase(),
    email = this.email,
    avatarColor = ColorGenerator.generate(this.id)
)

3. Библиотеки для маппинга

Для сложных проектов с большим количеством моделей использую MapStruct (через kapt) или Kotlinx.serialization с кастомными сериализаторами:

// Пример с MapStruct
@Mapper
interface UserMapper {
    @Mapping(source = "fullName", target = "name")
    fun toDomain(dto: UserDto): User
    
    @Mapping(source = "id", target = "displayId")
    @Mapping(target = "avatarColor", ignore = true)
    fun toUi(domain: User): UserUi
}

Лучшие практики, которые я применяю

  • Иммутабельность: все модели данных — data class с неизменяемыми свойствами (val)
  • Null-safety: явно обрабатываю nullable-поля на этапе маппинга
  • Валидация: проверяю и валидирую данные при преобразовании
  • Ленивые вычисления: для сложных преобразований UI-моделей использую by lazy
  • Тестирование: обязательно пишу unit-тесты для мапперов
@Test
fun `user dto to domain mapping correct`() {
    val dto = UserDto(1, "john doe", "john@test.com")
    val domain = userMapper.toDomain(dto)
    
    assertEquals(1L, domain.id)
    assertEquals("john doe", domain.name)
    assertEquals("john@test.com", domain.email)
}

Где происходит маппинг

  1. Репозитории — преобразуют DTO/Entity в Domain-модели
  2. UseCases/Interactors — работают только с Domain-моделями
  3. ViewModel/Presenter — преобразуют Domain в UI-модели
  4. Адаптеры, Composable функции — получают готовые UI-модели

Преимущества такого подхода

  • Изоляция изменений: при изменении API меняется только DTO и маппер
  • Тестируемость: domain-слой не зависит от деталей реализации
  • Читаемость: каждый слой имеет понятные, специализированные модели
  • Безопасность: валидация данных происходит в контролируемых точках

Правильный маппинг данных — это фундамент поддержуемой архитектуры, который окупается при первых же изменениях требований или API.

Как делал маппинг данных между слоями архитектуры | PrepBro