Event handling EventBus/PubSub vs(反应式扩展)RX在单线程应用程序中的代码清晰度
目前,我正在使用带有Scala(和JavaFX)的EventBus/architecture/pattern来实现一个简单的便笺组织应用程序(有点像Evernote客户端,带有一些额外的思维导图功能),我必须说,我真的喜欢EventBus而不是observer模式 以下是一些EventBus库: (目前似乎有所下降)这是我在实现中使用的一个 下面是EventBus库的比较: EventBus与 然而强> 最近,我开始思考使用而不是EventBus是否会在单线程应用程序中进一步简化事件处理代码 我想询问使用这两种技术(某种类型的eventbus库和某种形式的(RX))编程的人的经验:考虑到不需要使用多线程,使用RX比使用event bus架构更容易解决事件处理的复杂性吗 我问这个问题是因为我在中听说,与使用observer模式相比,使用observer模式可以产生更干净的代码(即没有“回调地狱”),但是我没有发现EventBus体系结构与observer模式之间的任何比较。因此,很明显,EventBus和RXJava都比observer模式好,但在单线程应用程序中,哪一个在代码清晰性和可维护性方面更好 如果我理解正确,它的主要卖点是,如果存在阻塞操作(例如等待服务器响应),它可以用于生成响应性应用程序 但我一点也不关心异步性,我所关心的只是在单线程应用程序中保持代码干净、不纠结、易于推理 在这种情况下,使用RXJava是否比使用EventBus更好 我认为EventBus将是一个更简单、更干净的解决方案,我看不出有任何理由支持简单的EventBus体系结构,而将RXJava用于单线程应用程序 但我可能错了强>Event handling EventBus/PubSub vs(反应式扩展)RX在单线程应用程序中的代码清晰度,event-handling,system.reactive,reactive-programming,event-bus,rx-java,Event Handling,System.reactive,Reactive Programming,Event Bus,Rx Java,目前,我正在使用带有Scala(和JavaFX)的EventBus/architecture/pattern来实现一个简单的便笺组织应用程序(有点像Evernote客户端,带有一些额外的思维导图功能),我必须说,我真的喜欢EventBus而不是observer模式 以下是一些EventBus库: (目前似乎有所下降)这是我在实现中使用的一个 下面是EventBus库的比较: EventBus与 然而 最近,我开始思考使用而不是EventBus是否会在单线程应用程序中进一步简化事件处理代码 我
如果我错了,请纠正我,并解释为什么在单线程应用程序中,如果没有执行阻塞操作,RXJava会比简单的EventBus更好。根据我上面的评论,JavaFx有一个类,它与RX
Observable
(更准确地说,可能是ConnectableObservable
,因为它允许多个订阅)。我使用以下隐式类将RX转换为JFX,如下所示:
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)
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 (...);
导入scala.collection.mutable.Map
导入javafx.beans.InvalizationListener
导入javafx.beans.value.ChangeListener
导入javafx.beans.value.observeValue
导入rx.lang.scala.Observable
导入rx.lang.scala.Subscription
/**
*包装器,允许RX可观察对象和JavaFX之间的互操作性
*可观察到的。
*/
对象JfxRxImplicitConversion{
隐式类JfxRxObservable[T](theObs:Observable[T])扩展了ObservableValue[T]{jfxRxObs=>
val InvalidListeners:Map[InvalidateListener,Subscription]=Map.empty
val ChangeListener:Map[ChangeListener[\u>:T],订阅]=Map.empty
var last:T=_
theObs.subscribe{last=}
覆盖def getValue():T=last
覆盖def addListener(arg0:invalizationListener):单位={
InvalistListeners+=arg0->theObs.subscribe{next:T=>arg0.invalidated(jfxRxObs)}
}
覆盖def RemovelListener(arg0:InvalizationListener):单位={
无效的侦听器(arg0)。取消订阅
无效侦听器-arg0
}
覆盖def addListener(arg0:ChangeListener[\u>:T]):单位={
changeListeners+=arg0->theObs.subscribe{next:T=>arg0.changed(jfxRxObs,last,next)}
}
覆盖def RemovelListener(arg0:ChangeListener[\u>:T]):单位={
changeListeners(arg0)。取消订阅
changeListeners-arg0
}
}
}
然后允许您像这样使用属性绑定(这是ScalaFX,但对应于JavaFX中的property.bind
):
新标签{
text以下是我认为在单线程同步应用程序中使用反应式事件流的好处
1.更多的声明性,更少的副作用和更少的可变状态。
事件流能够封装逻辑和状态,从而使代码没有副作用和可变变量
考虑一个计算按钮点击次数并将点击次数显示为标签的应用程序
普通Java解决方案:
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!!!
});
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());
class A {
public void f() {
eventBus.post(evt);
}
}
// during initialization
eventBus.register(consumer);
A a = new A();
class A {
public EventStream<MyEvent> events() { /* ... */ }
}
// during initialization
A a = new A();
a.events().subscribe(consumer);
ReactFX解决方案:
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!!!
});
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());
class A {
public void f() {
eventBus.post(evt);
}
}
// during initialization
eventBus.register(consumer);
A a = new A();
class A {
public EventStream<MyEvent> events() { /* ... */ }
}
// during initialization
A a = new A();
a.events().subscribe(consumer);
没有使用可变变量,对label.textProperty()
的副作用赋值隐藏在抽象后面
在他的硕士论文中,他提出将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)
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 (...);
它与前一种等效,具有消除控制反转的额外好处
2.消除故障和冗余计算的方法。(仅限ReactFX)
故障是可观察状态下的暂时不一致。ReactFX有方法暂停事件传播,直到对对象的所有更新都已处理完毕,以避免故障和冗余更新。特别是,请查看和。这些技术依赖于事件传播是同步的,因此不会转换为rxJava
3.明确事件生产者和事件消费者之间的联系。
事件总线是任何人都可以发布和订阅的全局对象。事件生产者和事件消费者之间的耦合是间接的,因此不太清楚。
对于反应性事件流,生产者和消费者之间的耦合更加明确