Нужно улучшить "очень неловкую" логику Rx для объединения разных источников данных - PullRequest
0 голосов
/ 04 февраля 2019

Мне недавно пришлось пройти технический тест для заявления о приеме на работу, спецификация для которого здесь .В их отзывах одной из вещей, которые им не понравились, была моя логика Rx для Screen 2 - объединение информации из трех отдельных вызовов API.Их точные слова были:

  • Для подробностей публикации ведущий очень неуклюж в логике Rx для объединения разных источников данных.Было бы действительно полезно иметь вариант использования вместо этого.
  • Знание операторов Rx отсутствует, часто используя неудобные решения

Ниже приведен код, на который они ссылаются:

apiService.getPost(view.postId)
    .subscribeOn(Schedulers.io())
    .map { posts -> posts[0] }
    .flatMap { post ->
        Observable.zip<String, String, String, String, PostDetails>(
            Observable.just(post.title),
            Observable.just(post.body),
            apiService.getUser(post.userId).subscribeOn(Schedulers.io()).map { it[0].username },
            apiService.getComments(post.id).subscribeOn(Schedulers.io()).map { it.size.toString() },
            Function4 { title, body, name, comments -> PostDetails(title, body, name, comments) }
        )
    }
    .observeOn(view.scheduler)
    .subscribe { view.showDetails(it) }

Ниже приведены интерфейсы Retrofit для некоторого контекста:

@GET("posts") fun getPost(@Query("id") postId: Int?): Observable<List<Post>>
@GET("users") fun getUser(@Query("id") userId: Int?): Observable<List<User>>
@GET("comments") fun getComments(@Query("postId") postId: Int?): i Observable<List<Comment>>

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

Как я могу улучшить это?В частности, какие операторы помогут привести это в порядок?

1 Ответ

0 голосов
/ 14 февраля 2019

Рассмотрите возможность включения RxKotlin ;у него есть хороший синтаксис zip из Observables, который не требует явных объявлений типов или уродливого Function4.Кроме того, вы можете использовать функции расширения, чтобы убедиться, что код настолько описателен, насколько это возможно, и больше функций в целом помогут аккуратно разделить «среднюю» логику и вложенные наблюдаемые.Например:

fun updatePostView() =
    apiService.getPost(view.postId)
        .subscribeOn(Schedulers.io())
        .map { it.first() }
        .createPostDetails()
        .observeOn(view.scheduler)
        .subscribeBy(
            onNext = { view.showDetails(it) },
            onError = { it.printStackTrace() }
        )

private fun Observable<out Post>.createPostDetails(): Observable<PostDetails> =
    flatMap { post ->
        Observables.zip(
            getPostTitle(post),
            getPostBody(post),
            getPostUser(post),
            getPostComments(post)
        ) { title, body, name, comments -> PostDetails(title, body, name, comments) }
    }

private fun getPostTitle(post: Post) =
    Observable.just(post.title)

private fun getPostBody(post: Post) =
    Observable.just(post.body)

private fun getPostUser(post: Post) =
    apiService.getUser(post.userId).subscribeOn(Schedulers.io()).map { it.first().username }

private fun getPostComments(post: Post) =
    apiService.getComments(post.id).subscribeOn(Schedulers.io()).map { it.size.toString() }

Конечно, это больше кода, но лучше читать.В противном случае кажется, что вы достаточно хорошо понимаете Rx-операторы в целом из того, что вы предоставили.

...