是否有任何rxjava运算符,例如节流阀,但没有过滤器?

时间:2019-12-28 01:43:18

标签: functional-programming rx-java rx-java2 throttling

假设有一个高速公路入口和一个停车标志。

以下是规则:

1,第一辆无需任何等待即刻进入高速公路的汽车。 2,在任何其他时间,其他汽车必须在前一辆汽车通过后至少等待2.5秒。 3,请注意,这并不意味着所有汽车都必须等待2.5秒。 例如,第一辆汽车立即通过。 10小时后,这是第二辆车。它应该立即通过,因为第一辆车已经过了10个小时,而这是很久以前的事了。 要求第二辆汽车等待2.5秒没有任何意义。但是,假设第二辆车出现后,第三辆车的显示时间为1200毫秒,这瞬间过去了。第三辆车需要等待1300毫秒。

我在github repo中有使用单元测试的代码,并且单元测试通过了。但是我真的不喜欢引入副作用的事实。

    private int passedCarCount;
    private int timeSpanCount;

因此,我正在编写此示例应用程序,希望让Rx专家优化代码。高度赞赏的是,如果我们能够以一种干净的方式完成它。

package com.tonytangandroid.rxjava_stop_sign.demo;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Scheduler;

public class ThrottleCarStream {

    private final CarStream carStream;
    private final Scheduler scheduler;
    private int passedCarCount;
    private int timeSpanCount;

    public ThrottleCarStream(CarStream carStream, Scheduler scheduler) {
        this.carStream = carStream;
        this.scheduler = scheduler;
    }


    public Observable<Car> periodUserActionStream() {
        return zip();
    }


    private Observable<Car> zip() {
        return Observable.zip(rawStream(), internal(), this::value);
    }

    private Observable<Long> internal() {
        return Observable.interval(0, 2500, TimeUnit.MILLISECONDS, scheduler)
            .doOnSubscribe(disposable -> initSpanCount())
            .filter(c -> whenCarCountGreaterOrEqualThanTimeSpanCount())
            .doOnNext(aLong -> increaseSpanCount());
    }

    private boolean whenCarCountGreaterOrEqualThanTimeSpanCount() {
        return passedCarCount >= timeSpanCount;
    }

    private void increaseSpanCount() {
        timeSpanCount++;
    }

    private void initSpanCount() {
        timeSpanCount = 0;
    }

    private Car value(Car cmdMessage, Long time) {
        return cmdMessage;
    }

    private Observable<Car> rawStream() {
        return carStream.cmdStream()
            .doOnSubscribe(disposable -> initElementCount())
            .doOnNext(cmdMessage -> increaseElementCount());
    }

    private void increaseElementCount() {
        passedCarCount++;
    }

    private void initElementCount() {
        passedCarCount = 0;
    }


}

1 个答案:

答案 0 :(得分:0)

这应该有效:

@RequiredArgsConstructor
public class DelayTransformer<T> implements ObservableTransformer<T, T> {
    private Long last = null;
    final long limit;

    @Override
    public ObservableSource<T> apply(final Observable<T> upstream) {
        return upstream.flatMap(x -> {
            final long current = System.currentTimeMillis();
            final long delay = last == null ?
                0 : Math.max(0, limit - (current - last));
            last = current + delay;
            return Observable.just(x).delay(delay, TimeUnit.MILLISECONDS);
        });
    }
}

// Caller
Observable<String> car1 = Observable
    .just("car1")
    .delay(100, TimeUnit.MILLISECONDS);
Observable<String> car2 = Observable
    .just("car2")
    .delay(200, TimeUnit.MILLISECONDS);
Observable<String> car3 = Observable
    .just("car3")
    .delay(2500, TimeUnit.MILLISECONDS);
Observable<String> cars = Observable
    .merge(car1, car2, car3);
cars
    .doOnNext(x -> log.info("Received: {}", x))
    .compose(new DelayTransformer<>(1500))
    .blockingSubscribe(x -> log.info("Emitted: {}", x));

我有以下输出:

[INFO ] 2019-12-28 01:11:06.107 [RxComputationThreadPool-1] App - Received: car1
[INFO ] 2019-12-28 01:11:06.128 [main] App - Emitted: car1
[INFO ] 2019-12-28 01:11:06.189 [RxComputationThreadPool-2] App - Received: car2
[INFO ] 2019-12-28 01:11:07.622 [main] App - Emitted: car2
[INFO ] 2019-12-28 01:11:08.490 [RxComputationThreadPool-3] App - Received: car3
[INFO ] 2019-12-28 01:11:09.122 [main] App - Emitted: car3