Чистая архитектура приложений для Android: если на уровне данных есть свои классы моделей?

Какой лучший подход при разработке приложения для Android и попытка следовать рекомендациям по чистой архитектуре (но не очень строгому – это может быть излишним для небольших проектов).

В моем случае я не уверен, какой подход является лучшим (если есть лучший) в отношении уровня данных, и если слой данных должен работать на своих собственных классах моделей или если он может работать непосредственно на моделях уровня домена.

Кроме того, если слой данных должен работать на своих собственных классах моделей, если источники данных, такие как DB или API имеют свои собственные модели (например, для API с использованием Retrofit и Gson – класс модели с аннотациями Gson ), а затем сопоставляются с моделями уровня данных или должны сама модель уровня данных является моделью, возвращаемой DB и API (это означает, что модель уровня данных должна быть аннотирована для того, чтобы Gson мог ее проанализировать в случае Retrofit и Gson ).

Это имеет место в этом проекте: https://github.com/android10/Android-CleanArchitecture/blob/master/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java

Следующие изображения должны прояснить три подхода:

В Image 1 DB и API возвращают определенные классы моделей. В случае API это может выглядеть (с использованием Retrofit и Gson ):

 class ArticleResponse(@SerializedName("source") val source: SourceResponse, @SerializedName("author") val author: String?, @SerializedName("title") val title: String, @SerializedName("description") val description: String?, @SerializedName("url") val url: String, @SerializedName("urlToImage") val urlToImage: String?, @SerializedName("publishedAt") val publishedAt: String?) 

Затем они отображаются локальными / удаленными источниками данных в модели Article (которые используются доменным уровнем). Поэтому репозиторий работает на моделях доменного уровня и нарушает границы? Это подход 1. Изображение1

В Image 2 DB и API прежнему возвращают определенные классы моделей. В случае API это может выглядеть (с использованием Retrofit и Gson ):

 class ArticleResponse(@SerializedName("source") val source: SourceResponse, @SerializedName("author") val author: String?, @SerializedName("title") val title: String, @SerializedName("description") val description: String?, @SerializedName("url") val url: String, @SerializedName("urlToImage") val urlToImage: String?, @SerializedName("publishedAt") val publishedAt: String?) 

Однако эти модели затем отображаются на модель уровня данных ( ArticleEntity ), на которой работает слой данных. При ответе на доменный уровень repository сопоставляет данные ArticleEntity с моделью уровня домена. Это не нарушает границы (справа), но для слоя данных требуется дополнительное отображение . Это подход 2.

введите описание изображения здесь

В Image 3 DB и API уже возвращают модель ArticleEntity уровне ArticleEntity . Поэтому этот класс модели должен содержать все аннотации, необходимые для анализа запроса API (с помощью Gson ):

 class ArticleEntity(@SerializedName("source") val source: SourceResponse, @SerializedName("author") val author: String?, @SerializedName("title") val title: String, @SerializedName("description") val description: String?, @SerializedName("url") val url: String, @SerializedName("urlToImage") val urlToImage: String?, @SerializedName("publishedAt") val publishedAt: String?) 

Если БД также нуждается в каких-то аннотациях, то они также должны быть добавлены в этот класс (правильно?). Преимущество такого подхода, о котором я могу думать, состоит в том, что классов моделей меньше (потому что DB и API напрямую сопоставляются с моделями на уровне данных). Однако разве это не взорвать класс модели данных с аннотациями / свойствами из всех разных источников данных (DB, API)? Разве не вся суть абстрагирования источников данных из репозитория нарушена тогда, потому что модель уровня данных зависит от конкретной реализации источника данных (например, используя Gson для анализа запроса API с точными именами ответов API). Таким образом, это был подход 3.

введите описание изображения здесь

Мой вопрос: какой из трех подходов является наиболее гибким и перспективным?

Если бы я был вами, я бы пошел с процессом Image1. Я думаю, что работа вашего источника данных заключается в том, чтобы взять любой объект из вашей базы данных или API или любой конечной точки, которая у вас есть, и превратить ее в что-то более удобное для пользователя в вашем репозитории.

Между Image1 и Image2 я думаю, что это зависит от того, какие данные вы хотите сохранить и каков объект, который вы хотите сохранить. Вы можете или не нуждаетесь в ArticleEntity в зависимости от ваших бизнес-правил. И если вам это не нужно, вам не нужно его создавать.

Но для некоторых случаев использования вам может понадобиться создать этот объект, чтобы добавить некоторую информацию в вашу статью. Например, если вы хотите указать дату действия или любую другую информацию, которую будете использовать только в своем репозитории, вы можете перейти к Image2.