Сначала использовать офлайн или тот, который вы видите в официальном документе и чистую архитектуру с отображением DTO (объект передачи данных, используемый для получения данных REST) в модель базы данных Entity?
С помощью При автономном подходе «первый / последний» вам необходимо иметь 3 разных типа модели для одних и тех же данных и иметь 2 преобразования, которые:
DTO(Data from network) -> Entity(Database/Room @Entity) -> Item(For presentation or UI)
Второе преобразование - это то, что каждый пример делает на уровне использования или домена. Вопрос здесь в том, где преобразовать из сетевой модели в модель базы данных.
Один дизайн, который я видел в приложении Buffer в github, выглядит примерно так: он немного упрощен,
interface PostDataSource {
suspend fun getPostEntities(): List<PostEntity>
}
interface LocalPostDataSource : PostDataSource {
suspend fun savePosts(posts: List<PostEntity>)
suspend fun deletePosts()
}
interface RemotePostDataSource : PostDataSource
все дело в как удаленный, так и локальный источник данных возвращают объекты базы данных, где отображение logi c происходит внутри удаленного реализации источника данных.
class RemotePostDataSourceImpl(
private val postApi: PostApi,
private val mapper: DTOtoEntityMapper
) : RemotePostDataSource {
override suspend fun getPostEntities(): List<PostEntity> {
return mapper.map(postApi.getPosts())
}
}
А в другом я обычно вижу
interface PostDataSource
interface LocalPostDataSource : PostDataSource {
suspend fun getPostEntities(): List<PostEntity>
suspend fun savePosts(posts: List<PostEntity>)
suspend fun deletePosts()
}
interface RemotePostDataSource : PostDataSource {
suspend fun getPostDTOs(): List<PostDTO>
}
удаленный источник данных
class RemotePostDataSourceImpl(
private val postApi: PostApi
) : RemotePostDataSource {
override suspend fun getPostDTOs(): List<PostDTO> {
return postApi.getPosts()
}
}
И сопоставление logi c находится внутри репозитория
class PostRepositoryImpl(
private val localPostDataSource: LocalPostDataSource,
private val remotePostDataSource: RemotePostDataSource,
private val mapper: DTOtoEntityMapper
) : PostRepository {
override suspend fun getPostsOfflineFirstFlow(): Flow<List<PostEntity>> =
flow {
emit(localPostDataSource.getPostEntities())
}
.flatMapConcat { postEntities ->
if (postEntities.isNullOrEmpty()) {
mapper.map(remotePostDataSource.getPostDTOs())?.apply {
localPostDataSource.deletePosts()
localPostDataSource.savePosts(this)
}
flowOf(localPostDataSource.getPostEntities())
} else {
flowOf(postEntities)
}
}.catch { emit(listOf()) }
}
Не обращайте внимания на остальную часть кода, кроме сопоставления для этого вопроса, он вызывается в репозитории.
И мой второй вопрос заключается в том, что не помещает c бизнес-логику в репозиторий или удаленный источник данных вместо варианта использования / интерактора (класс с целью реализации бизнес-логи c) для автономного первого рассматриваемого анти-шаблона?
Изменить : Без модели для базы данных / сети / пользовательского интерфейса, сопоставления и источников данных Google предложил код для получение данных с удаленного компьютера и сохранение в БД выполняется на уровне репозитория. Было бы лучше переместить logi c для проверки данных retrieving
, refreshing
и cacheing
на уровень домена, если вы считаете, что это анти-шаблон, чтобы иметь logi c в репозитории или источниках данных?
// Informs Dagger that this class should be constructed only once.
@Singleton
class UserRepository @Inject constructor(
private val webservice: Webservice,
// Simple in-memory cache. Details omitted for brevity.
private val executor: Executor,
private val userDao: UserDao
) {
fun getUser(userId: String): LiveData<User> {
refreshUser(userId)
// Returns a LiveData object directly from the database.
return userDao.load(userId)
}
private fun refreshUser(userId: String) {
// Runs in a background thread.
executor.execute {
// Check if user data was fetched recently.
val userExists = userDao.hasUser(FRESH_TIMEOUT)
if (!userExists) {
// Refreshes the data.
val response = webservice.getUser(userId).execute()
// Check for errors here.
// Updates the database. The LiveData object automatically
// refreshes, so we don't need to do anything else here.
userDao.save(response.body()!!)
}
}
}
companion object {
val FRESH_TIMEOUT = TimeUnit.DAYS.toMillis(1)
}
}