EventBus/PubSub vs(反应式扩展)RX关于单线程应用程序中的代码清晰度

jhe*_*dus 37 event-handling reactive-programming system.reactive event-bus rx-java

目前,我正在使用带有Scala(和JavaFX)的EventBus/PubSub架构/模式来实现一个简单的笔记组织应用程序(有点像Evernote客户端,带有一些添加的思维导图功能),我不得不说我真的很喜欢EventBus观察者模式.

以下是一些EventBus库:

https://code.google.com/p/guava-libraries/wiki/EventBusExplained

http://eventbus.org(目前似乎已经失效)这是我在实施中使用的那个.

http://greenrobot.github.io/EventBus/

以下是EventBus库的比较:http://codeblock.engio.net/37/

EventBus与发布 - 订阅模式相关.

但是!

最近,我参加了CourseraReactive课程并开始怀疑使用RXJava而不是EventBus是否会在单线程应用程序中简化事件处理代码?

我想问一下关于使用这两种技术(某种eventbus库谁编程的人的经验某种形式的反应扩展(RX)):是很容易解决的事件处理使用RX复杂性比与事件总线架构给出没有必要使用多个线程

我问这个,因为我已经在听到无功讲座CourseraRX(即没有"回调地狱")导致更清洁的代码比使用观察者模式,但是我没有找到VS EventBus架构之间的任何比较RXJava.所以很明显,EventBus和RXJava都比观察者模式更好,但 在代码清晰度和可维护性方面,它在单线程应用程序更好

如果我理解正确的话,RXJava的主要卖点是,如果存在阻塞操作(例如,等待来自服务器的响应),它可用于生成响应式应用程序.

但我根本不关心异步性,我所关心的只是在单线程应用程序中保持代码清洁,解开并易于推理.

在这种情况下,使用RXJava比使用EventBus更好吗?

我认为EventBus将是一个更简单,更清晰的解决方案,我认为没有任何理由可以将RXJava用于单线程应用程序,而采用简单的EventBus架构.

但我可能错了!

如果我错了,请纠正我,并解释为什么RXJava在单线程应用程序中没有执行阻塞操作的情况下比简单的EventBus更好.

Tom*_*ula 30

以下是我认为在单线程同步应用程序中使用反应事件流的好处.

1.更具说服力,副作用更少,可变状态更少.

事件流能够封装逻辑和状态,可能使代码没有副作用和可变变量.

考虑一个计算按钮点击次数并将点击次数显示为标签的应用程序.

简单的JavaFX解决方案:

private int counter = 0; // mutable field!!!

Button incBtn = new Button("Increment");
Label label = new Label("0");

incBtn.addEventHandler(ACTION, a -> {
    label.setText(Integer.toString(++counter)); // side-effect!!!
});
Run Code Online (Sandbox Code Playgroud)

ReactFX解决方案:

Button incBtn = new Button("Increment");
Label label = new Label("0");

EventStreams.eventsOf(incBtn, ACTION)
        .accumulate(0, (n, a) -> n + 1)
        .map(Object::toString)
        .feedTo(label.textProperty());
Run Code Online (Sandbox Code Playgroud)

没有使用可变变量,并且副作用赋值label.textProperty()隐藏在抽象之后.

在他的硕士论文中,Eugen Kiss提出将ReactFX与Scala集成.使用他的集成,解决方案可能如下所示:

val incBtn = new Button("Increment")
val label = new Label("0")

label.text |= EventStreams.eventsOf(incBtn, ACTION)
    .accumulate(0, (n, a) => n + 1)
    .map(n => n.toString)
Run Code Online (Sandbox Code Playgroud)

它与前一个相同,具有消除控制反转的额外好处.

2.消除毛刺和冗余计算的方法.(仅限ReactFX)

毛刺是可观察状态的暂时不一致.ReactFX具有暂停事件传播的方法,直到处理完对象的所有更新,避免了毛刺和冗余更新.特别是,看看可暂停的事件流,Indicator,InhiBeans我关于InhiBeans的博客文章.这些技术依赖于事件传播是同步的事实,因此不会转换为rxJava.

3.清除事件生成者和事件使用者之间的连接.

事件总线是一个全局对象,任何人都可以发布和订阅.事件生成者和事件使用者之间的耦合是间接的,因此不太清楚.对于反应事件流,生产者和消费者之间的耦合更加明确.相比:

活动巴士:

class A {
    public void f() {
        eventBus.post(evt);
    }
}

// during initialization
eventBus.register(consumer);
A a = new A();
Run Code Online (Sandbox Code Playgroud)

之间的关系a,并consumer不能从看着眼前的初始化代码清晰.

事件流:

class A {
    public EventStream<MyEvent> events() { /* ... */ }
}

// during initialization
A a = new A();
a.events().subscribe(consumer);
Run Code Online (Sandbox Code Playgroud)

a和之间的关系consumer非常明确.

4.对象发布的事件在其API中表现出来.

使用上一节中的示例,在事件总线示例中,AAPI不会告诉您实例发布了哪些事件A.另一方面,在事件流示例中,A's API声明A了类型的发布事件的实例MyEvent.

  • 在你的观点#3,"布线"松散的事实是事件总线的优势,而不是我认为的弱点.从消费者的角度来看,发布活动的人并不重要.反之亦然,从出版商的角度来看,它并不关心谁接收它 - 谁愿意倾听和反应,谁就可以.这就是pub/sub架构的美妙之处.至少这是我对它的理解. (8认同)
  • @JihoHan你所说的对于我在第3点的例子仍然是正确的:`A`并不关心谁,如果有人,消耗它产生的事件,而'消费者'并不关心是谁产生了这个事件.额外的好处是接线代码确定'A`能够产生类型为'MyEvent`的事件,并且`consumer`能够消耗它们.这为您提供更多类型安全性.太多的自由(与全局事件总线一样)降低了推理代码的能力. (2认同)

Rog*_*eto 5

我认为你必须使用rxjava,因为它提供了更大的灵活性.如果你需要一辆公共汽车,你可以使用这样的枚举:

public enum Events {

  public static PublishSubject <Object> myEvent = PublishSubject.create ();
}

//where you want to publish something
Events.myEvent.onNext(myObject);

//where you want to receive an event
Events.myEvent.subscribe (...);
Run Code Online (Sandbox Code Playgroud)

.