在给flatMap的RxJava Func1对象中使用可变状态是个好主意吗?

时间:2017-10-31 16:42:29

标签: java rx-java reactive-programming

假设我们需要以一种我们需要知道其所有先前发射的项目的方式转换热Observable,以便能够确定接下来要发射的内容。我发现最方便的解决方案是传递Func1子类的实例,该子类具有全局状态(例如,先前发出的项的映射或列表)到flatMap。在每次调用中,Func1实例将更新其状态,并根据该状态决定返回什么。

但是,我很担心"好看"这个解决方案。据我所知,RxJava在全局和可变状态下表现不佳,这种解决方案似乎与之形成鲜明对比。另一方面,我确信我的Observable符合Observable合同,因此它似乎至少是一个有效的解决方案,如果可以同时调用它,则同步可以解决问题。

其他可能的解决方案可能是:

  1. 创建运营商。我想,允许运算符中的可变状态。无论如何,我试图避免使用自定义操作符,因为它们更棘手。

  2. 通过扫描(在列表或地图中)传播Observable的历史记录。我会为每个发出的项目使用相同的对象(List或Map),这会将可变对象引入流中,或者每次都复制整个对象,这会浪费很多性能。

  3. 订阅原始的Observable,从订阅者修改一些全局状态,并使用此全局状态在Subject(转换后的Observable)上发出项目。我想到了这一点,因为它似乎在处理全局状态(和同步)时退出了RxJava的范围。

  4. 所以问题是:我应该在flatMap中使用具有可变状态的Func1实现来根据先前发出的项目(有效,顺便说一句)的历史转换项目,如果没有,我应该使用哪些替代方案?一般来说,我对处理变换Observable所需的复杂可变状态的推荐方法感到困惑。

    我希望我能清楚地表达我的问题。否则,请告诉我,我会尝试在某些特定问题和代码的帮助下对其进行描述。

2 个答案:

答案 0 :(得分:2)

通常不建议使用包含可变状态的函数的流,因为可变状态可能跨多个Subscriber共享到特定的Observable链。但是,大多数开发人员经常在需要时汇集Observable,并且很少重复使用相同的Observable。例如,按钮单击处理程序将创建一个Observable,通过组合,分叉两个Observable以异步从两个不同的位置获取数据,然后订阅此线程本地{{1实例。新的按钮点击将使用全新且独立的Observable重复此过程。

这是您的有状态函数问题的解决方案:使有状态位的存在取决于订阅的各个订阅者:Observable

defer()

由于将为每个Observable<Integer> o = Observable.defer(() -> { return Observable.range(1, 10) .map(new Func1<Integer, Integer>() { int sum; @Override public Integer call(Integer v) { sum += v; return sum; } }); }); o.subscribe(System.out::println); o.subscribe(System.out::println); 调用创建Func1内部类,因此其subscribe字段对于每个消费者来说都是本地的。还要注意,sum被返回并自动装入一个不可变的sum,然后可以在其他一些线程(想想Integer)之后自由读取,因为它完全脱离了{ {1}}字段然后开启。

答案 1 :(得分:1)

有用的工作通常需要可变状态和共享的可变状态。问题是我们如何将可变性与外部各方隔离开来。

  1. 创建运算符会隐藏运算符实例中的可变性。缺点是该州是可观察链的私人所在。
  2. Collections.reverse(arrayPeople); scan()reduce()(如果存在)将是很好的候选人,但他们的实施非常有限,以非显而易见的方式导出他们的状态,并且也仅限于他们所附带的可观察链条。
  3. fold()Subject个对象提供了有用的剪切点。
  4. 回到基础,以线程安全的方式使用可私有访问的数据结构并不是一件坏事。如果您只关心一个观察链,那么选项1或3中的任何一个都可以轻松完成工作。