RxJava Условный способ очистки FlatMap

Я ищу более чистый способ создания условного flatMap(), я прочитал this, но у меня возникли проблемы с его применением в моем коде:

// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)

// example
stringSingle
   .flatMap { string -> 
      if (string == "cat") {
         return@flatMap isCatEat()
             .flatMap { isCatEat ->
                if (isCatEat) { // if cat already ate, proceed immediately
                    Single.fromCallable { true }
                } else { // if not, feed cat
                   feedCat()
                }
             }
      } else {
         Single.fromCallable { false }
      }
   }

как вы можете видеть (ну, код очень уродлив, вложенность тьфу), я хочу избежать вызова feedCat(), сначала проверив его, если кошка уже съела. У меня возникли проблемы с применением функции compose(), так как я не могу воспроизвести свое состояние.


person Tenten Ponce    schedule 11.04.2019    source источник


Ответы (2)


Я извлек второй if в расширенную функцию

// given variables for the sake of simplicity
val stringSingle = Single.just("dog")
val isCatEat = Single.just(true)
val feedCat = Single.just(true)

// example
stringSingle
        .flatMap { string ->
            if (string == "cat") {
                isCatEat.flatMapIfTrue { feedCat }
            } else {
                Single.fromCallable { false }
            }
        }

Где:

fun Single<Boolean>.flatMapIfTrue(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
        this.flatMapIf({ it }, mapper)

fun Single<Boolean>.flatMapIfFalse(mapper: (Boolean) -> Single<Boolean>): Single<Boolean> =
        this.flatMapIf({ !it }, mapper)

fun <T> Single<T>.flatMapIf(conditions: (T) -> Boolean, mapper: (T) -> Single<T>): Single<T> =
        this.flatMap {
            if (conditions(it)) mapper(it)
            else Single.just(it)
        }

Я предоставил 3 fun, чтобы вы могли повторно использовать их в других местах.

person borichellow    schedule 11.04.2019
comment
Судя по тому, что я вижу, вы перенесли процесс на другую функцию. Так намного чище. Но я все равно подожду другого ответа, который может использовать существующие операторы в rxjava. - person Tenten Ponce; 12.04.2019

Вы можете использовать filter, который будет выдавать только в том случае, если предикат удовлетворен.

Я полагаю, вы хотите знать, когда эту кошку нужно кормить. Поэтому я думаю, что наблюдаемый будет более подходящим:

private val hasCatEaten = Single.just(true)

fun feedCat(animal: String): Observable<Unit> =
        Observable.just(animal)
                .filter { it == "cat" }
                .flatMapSingle { hasCatEaten }
                .filter { !it }
                .map { Unit }

fun observeFeedCat() {
    feedCat("cat")
            .subscribeOn(schedulers.ioScheduler())
            .observeOn(schedulers.mainScheduler())
            .subscribeBy(onNext = { // Called when cat needs to be fed })
            .addTo(disposables)
}

ОБНОВЛЕНИЕ

Это лучшее решение, которое обрабатывает оба случая:

    fun shouldFeed(animal: String): Single<Boolean> =
        Single.fromCallable { animal }
                .filter { it == "cat" }
                .flatMap { Maybe.fromCallable { !hasEaten } }
                .toSingle(false)

Я тестировал этот код (не кошка, кошка съела и кошка не съела), поэтому я вполне уверен в этом ответе.

person Iain    schedule 11.04.2019
comment
Извините, но я также хочу знать, не ест ли кот еще. Другими словами, я не хочу обрабатывать только, если условие выполнено, я также хочу обрабатывать, если оно не выполняется. - person Tenten Ponce; 12.04.2019
comment
Хорошо, не волнуйтесь. Смотрите обновление выше. Дайте мне знать, как вы поживаете. - person Iain; 12.04.2019
comment
Я использовал расширение от Бориса (см. выше), но спасибо за это, я также попробую это, если столкнусь с другой подобной проблемой. - person Tenten Ponce; 15.04.2019
comment
Нет необходимости иметь эти функции расширения. Зачем это делать, если Rx уже предоставляет необходимые операторы? Мое решение намного чище. - person Iain; 15.04.2019
comment
Хм, ладно, сначала попробую, потом вернусь, рефакторинг занимает некоторое время. - person Tenten Ponce; 15.04.2019
comment
Кажется, я не могу использовать это, потому что hasEaten — это Single, который возвращает true или false. А также, как только вы используете фильтр, он будет испускать, только если это правда. Может быть, я просто немного запутался, если вы можете использовать заданные мной переменные в своем решении, возможно, я смогу его интегрировать. - person Tenten Ponce; 23.04.2019