Вы в примере показали, что класс PersonSrc знает про класс PersonDst и наоборот. На более сложной структуре данных эта связанность будет кошмарной.
Вовсе нет. Я показал один пример, когда Src зависим от Dst, и другой пример, когда Dst зависим от Src. Это разные примеры. Конечно, когда они зависимы друг от друга – это антипример будет.
Про низкую связанность:
Во-первый, ограничение видимости полей класса ведет к уменьшению связанности кода. В примере с методами как раз можно ограничить видимость. Не очень хорошо, когда маппинг заставляет делать поля открытыми.
Во-вторых, давайте сравним такие варианты кода.
Вариант А:
// файл 1
class EntitySrc(private val id: Int) {
fun mapToDst(src: EntitySrc) = EntityDst(src.id)
}
// файл 2
class EntityDst(val id: Int)
Вариант Б:
// файл 1
class EntitySrc(val id: Int)
// файл 2
class EntityDst(val id: Int)
// файл 3
fun mapEntity(src: EntitySrc) = EntityDst(src.id)
В варианте А EntitySrc зависит от EntityDst: итого 1 зависимость.
В варианте Б mapEntity зависит от EntitySrc и от EntityDst: итого 2 зависимости.
Т.е. слои, конечно, в варианте Б лучше выражены, но весь код в итоге более связан.
Чтобы быть ближе к практике, можно рассмотреть типичную задачу: добавление одного поля и пробрасывание его через все слои. Задача возникает постоянно. В варианте А надо модифицировать только 2 файла, в варианте Б, надо модифицировать 3 файла. Меньше связей – меньше работы для модификации.
ps: каким образом моки помогут в тестировании маппинга моделей?
Если мы используем методы-мапперы и хотим протестировать только один маппер нам надо написать такой код:
internal class PersonSrcTest {
@Test
fun mapToDestination() {
val salarySrc: SalarySrc = mock(SalarySrc::class.java)
`when`(salarySrc.mapToDestination()).thenReturn(SalaryDst(0))
val personSrc = PersonSrc("Somebody", salarySrc)
val mapped = personSrc.mapToDestination()
assertEquals("Somebody", mapped.name)
}
}
Моки нужны чтобы при тестировании PersonSrc.mapToDestination не создавать настоящий объект SalarySrc и не вызывать SalarySrc. mapToDestination. И то и другое сделают этот тест избыточным.
Вовсе нет. Я показал один пример, когда Src зависим от Dst, и другой пример, когда Dst зависим от Src. Это разные примеры. Конечно, когда они зависимы друг от друга – это антипример будет.
Про низкую связанность:
Во-первый, ограничение видимости полей класса ведет к уменьшению связанности кода. В примере с методами как раз можно ограничить видимость. Не очень хорошо, когда маппинг заставляет делать поля открытыми.
Во-вторых, давайте сравним такие варианты кода.
Вариант А:
Вариант Б:
В варианте А EntitySrc зависит от EntityDst: итого 1 зависимость.
В варианте Б mapEntity зависит от EntitySrc и от EntityDst: итого 2 зависимости.
Т.е. слои, конечно, в варианте Б лучше выражены, но весь код в итоге более связан.
Чтобы быть ближе к практике, можно рассмотреть типичную задачу: добавление одного поля и пробрасывание его через все слои. Задача возникает постоянно. В варианте А надо модифицировать только 2 файла, в варианте Б, надо модифицировать 3 файла. Меньше связей – меньше работы для модификации.
Если мы используем методы-мапперы и хотим протестировать только один маппер нам надо написать такой код:
Моки нужны чтобы при тестировании PersonSrc.mapToDestination не создавать настоящий объект SalarySrc и не вызывать SalarySrc. mapToDestination. И то и другое сделают этот тест избыточным.