如何用rx-java替换“if语句”以避免回调地狱?

2022-09-02 22:04:04

我正在尝试用rx-java替换我的代码。(这是非常小的代码。

它完成了,它工作了。

但我想知道...

  1. 这是一个好的Rx风格吗?
  2. 如果不好,请注明不好点

下面是我的 api 处理代码。

以前

Random r = new Random();
boolean apiResult = r.nextBoolean(); // it represents api result. ex. {"result": true} or {"result": false}

if (apiResult == true) {
    // do something

    System.out.println("result:" + "success");
} else {
    // do something

    System.out.println("result:" + "failure");
}

Random r = new Random();
Observable<Boolean> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
    @Override
    public void call(Subscriber<? super Boolean> subscriber) {
        // emit true or false
         subscriber.onNext(r.nextBoolean());
    }
}).cache(1);


// I used filter for split. Is it Rx style?
// success if true emitted.
Observable<Boolean> successStream = apiResultStream
        .filter(aBoolean -> aBoolean == true); // here

// failure if false emitted.
Observable<Boolean> failureStream = apiResultStream
        .filter(aBoolean -> aBoolean == false); // here


// success flow
successStream
        .flatMap(aBoolean -> Observable.just("success"))
        // and do something
        .subscribe(aString -> System.out.println("result:" + aString));

// failure flow
failureStream
        .flatMap(aBoolean -> Observable.just("failure"))
        // and do something.
        // I want to keep subscriber.
        .subscribe(aString -> System.out.println("result:" + aString));

编辑

我几乎被替换了。感谢您的好评。
(但我有一些未替换的代码。它有许多回调和 if 语句。

我想避免“回调地狱”。

关键是“callSuccessApi”和“callFailureApi”之间的不同结果类型。

在 rx 之前

// callback hell!
callApi(new Callback<Result>(){
    @Override
    public void success(Result result) {
        if (result.Response == true) {
            callSuccessApi(new Callback<ResultSuccess>(){
                @Override
                public void success(ResultSuccess result) {
                    // and more callbacks...
                }
            }
        } else { // result.Response == false
            callFailureApi(new Callback<ResultFailure>(){
                @Override
                public void success(ResultFailure result) {
                    // and more callbacks...
                }
            }
        }
    }
}

使用rx后(避免回调地狱!这是一个好的Rx风格吗?

// change 1st api to observable.(I changed other api to observable)
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
    @Override
    public void call(Subscriber<? super Boolean> subscriber) {
        callApi(new Callback<Result>(){
            @Override
            public void success(Result result) {
                subscriber.onNext(result);
            }
        });
    }
}).cache(1); // ensure same Observable<Result> for success and failure.


// I used filter for split. Is it Rx style?
// success if result.response == true.
Observable<ResultSuccess> successStream = apiResultStream
        .filter(result -> result.response == true); // here

// failure if result.response == false.
Observable<ResultFailure> failureStream = apiResultStream
        .filter(result -> result.response == false); // here


// success flow. callSuccessApi return Observable<ResultSuccess>
successStream
        .flatMap(result -> callSuccessApi(result))
        // and more api call with flatMap...
        .subscribe(resultSuccessN -> System.out.println("result:" + resultSuccessN.toString()));

// failure flow. callFailureApi return Observable<ResultFailure>
failureStream
.flatMap(resultFailure -> callFailureApi(result))
        // and more api call with flatMap...
        .subscribe(resultFailureN -> System.out.println("result:" + resultFailureN.toString()));

对不起我的英语不好和长问题。

更新了我的代码

我在这个问题中得到了2个重要信息。(谢谢@Tomáš德沃夏克,@Will

  1. 这是否是一个好方法取决于具体情况。
  2. 在地图/平面地图/订阅中使用if语句没有错。

更新的代码

Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
        @Override
        public void call(Subscriber<? super Boolean> subscriber) {
            callApi(new Callback<Result>() {
                @Override
                public void success(Result result) {
                    subscriber.onNext(result);
                }
            });
        }
    });

    // In this case,   I used 'if' for simply and cleanly.
    apiResultStream
            .subscribe(result -> {
                if (result.response == true) {
                    callSuccessApi(); // this line looks like 'callback'. but I used this for simply and cleanly.
                } else {
                    callFailureApi();
                }
            });

答案 1

有很多方法可以做到这一点,这实际上取决于您的用例。一般来说,我不想分成2个流,因为这会降低代码的可读性。另外,我不确定你从flatMap调用中得到什么好处。在地图调用中执行 if 操作没有错。

以下是一些选项:

1 - 对于添加日志记录(有点像您的打印行),我使用doOnEach()

apiResultStream
  .doOnEach(next -> {
    if (next) logger.info("Logging true " + next);
    else  logger.info(Logging false " + next);
  })
  .subscribe(....

2 - 您正在执行的工作是流的一部分,您以后需要对流执行更多工作 - 使用map

apiResultStream
  .map(next -> {
        if (next) doSomeCallWithNextWhenTrue(next);
        else doSomeCallwithNextWhenFalse(next);
      })
  .subscribe(...

3 - 如果这是你想在管道结束时执行的工作 - 在所有转换或其他流类似工作完成后,IE,然后在订阅调用中执行此操作。

apiResultStream
  .subscribe(next -> {
            if (next) doSomeCallWithNextWhenTrue(next);
            else doSomeCallwithNextWhenFalse(next);
          });

问题是 - 对于这样一个简单的用例,很难提出最佳选择,但我欣赏在学习Rx时,研究如何做条件语句似乎令人困惑。通常,我只是使用或当我调用另一个返回的方法并在那里执行我的逻辑时。mapflatMapObservable

更新

仍然不确定为什么要拆分流。除非你开始聪明地使用不同的线程,否则第一个订阅调用将阻止第二个,这可能不是你想要的。此外,如果您没有多次呼叫订阅,则不需要该呼叫。cache()

在 / / 中使用 a 没有错。特别是如果它使您的代码更具可读性。if statementmapflatmapsubscribe

我会做以下事情:

apiResultStream
  .flatMap(result -> {
    if (result.response == true) {
      return callSuccessApi(result)
    }
    else {
      return callFailureApi(result)
  })
  //Do any more calls you need
  .subscribe(...

更干净。

我对您在订阅中的电话有点困惑。这是出于调试或日志记录目的吗?如果是这样,只需在上面的if语句中的flatMap中执行此操作即可。System.out.println

希望这有帮助,


答案 2

为了避免if/else并且不破坏链™,我喜欢使用发布和合并来拆分和重新合并流:

apiResultStream
  .publish(results -> 
    Observable.merge(
        results.filter(result -> result.response == true)
               .flatmap(result -> callSuccessApiObservable()),
        results.filter(result -> result.response == false)
               .flatmap(result -> callFailureApiObservable())
    )
  )
  .subscribe(...

推荐