私は、反応性のプログラミングに非常に新しいです。私は関数型プログラミングとkotlinコルーチンに非常に精通していますが、私はまだ、プレーン、ネストされたCRUDコード、ネストされた非同期操作で特にをリファクタリングする反応性プログラミングパラダイムを使用する方法を見つけ出すことはできません。
例えば、以下のCRUDコード非同期シンプルは、Java 8に基づいてスニペットであります CompletableFuture
getFooAsync(id)
.thenAccept(foo -> {
if (foo == null) {
insertFooAsync(id, new Foo());
} else {
getBarAsync(foo.bar)
.thenAccept(bar -> {
updateBarAsync(foo, bar);
});
}
});
これは、非同期性を失うことなく、それははるかに読みやすくkotlinのコルーチン、とそれをリファクタリングするのは非常に簡単です。
val foo = suspendGetFoo(id)
if(foo==null) {
suspendInsertFoo(id, Foo())
} else {
val bar = suspendGetBar(foo.bar)
suspendUpdateBar(foo, bar);-
}
しかし、反応性プログラミングに適したそのようなコードはありますか?
もしそうなら、与えられたFlux<String> idFlux
原子炉3でそれをリファクタリングする、どのように?
それだけで、すべてを交換することをお勧めしCompletableFuture
てMono
?
反応性プログラミングに適したそのようなコードはありますか?
IMHO、Kotlinのコルーチンはより良いこのユースケースに適しており、非常にクリーンなコードになります。
しかし、あなたがすることができ、反応ストリームでこれを行います。
それだけでモノを持つすべてのCompletableFutureを交換することをお勧めしますか?
私は、(例えば、反応ストリームは非常によく非同期ユースケースの多くを扱うことがわかってきたプロジェクトの原子炉からの例)。しかし、確かに非常に適合しないいくつかのユースケースがあります。だから、私は交換の方針お勧めすることはできませんすべてのを CompletableFuture
反応ストリームとを。
しかし、あなたから離れて切り替える必要があるために一つのケースは、CompletableFuture
あなたが背圧を必要とするときです。
使用するパターンは、言語/フレームワーク/ツール/ライブラリに依存非同期(async)あなたが使用して、どのように快適なあなたとあなたのチームメイトは彼らとされているかについての決定がたくさん。あなたは良いKotlinをサポートしているライブラリを使用している、とあなたのチームはKotlinに精通している場合は、コルーチンを使用しています。同様に、反応性ストリームのため。
与えられ
Flux<String> idFlux
、どのように反応器3でそれをリファクタリングしますか?
ここでは、このユースケースのための反応性のストリームを検討する際に注意すべき点は以下のとおりです。
- 反応ストリームは放出することはできません
null
。代わりに、空はMono
一般的に使用されています。(あなたは、技術的にも使用することができMono<Optional<...>>
ますが、その時点であなたは自分の脳を傷つけているとバグのために物乞い) - ときは
Mono
空で、ラムダはと取引することを任意の演算子に渡されたonNext
信号は、(例えば.map
、.flatMap
、.handle
、など)されて呼び出されません。あなたはの流れを扱っていることを覚えておいてくださいデータ(むしろ不可欠な制御フローより) .switchIfEmpty
または.defaultIfEmpty
演算子は、空の上で動作することができMono
、S。しかし、彼らが提供していないelse
状態を。下流オペレータは、ストリームが(に渡さパブリッシャから放出された要素がない限り、以前に空であったことに気付いていない.switchIfEmpty
識別可能何とか容易です)- あなたは多くのオペレータの流れがあり、複数のオペレータは、ストリームが空になることを引き起こす可能性がある場合は下流事業者が判断するのは、それが困難/不可能だ、なぜストリームが空になりました。
- 上流のオペレータから放出された値を処理できるようにメイン非同期演算子であり
.flatMap
、.flatMapSequential
そして.concatMap
。あなたは、以前の非同期操作の出力を操作チェーンの非同期操作にこれらを使用する必要があります。 - あなたのユースケースがないので返す値を、反応性ストリームの実装が返されます
Mono<Void>
そのすべてが、ここでは(いくつかの注意点との)反応器3にあなたの例を変換しようとする試みだと述べました。
Mono<Void> updateFoos(Flux<String> idFlux) {
return idFlux // Flux<String>
.flatMap(id -> getFoo(id) // Mono<Foo>
/*
* If a Foo with the given id is not found,
* create a new one, and continue the stream with it.
*/
.switchIfEmpty(insertFoo(id, new Foo())) // Mono<Foo>
/*
* Note that this is not an "else" condition
* to the above .switchIfEmpty
*
* The lambda passed to .flatMap will be
* executed with either:
* A) The foo found from getFoo
* OR
* B) the newly inserted Foo from insertFoo
*/
.flatMap(foo -> getBar(foo.bar) // Mono<Bar>
.flatMap(bar -> updateBar(foo, bar)) // Mono<Bar>
.then() // Mono<Void>
) // Mono<Void>
) // Flux<Void>
.then(); // Mono<Void>
}
/*
* @return the Foo with the given id, or empty if not found
*/
abstract Mono<Foo> getFoo(String id);
/*
* @return the Bar with the given id, or empty if not found
*/
abstract Mono<Bar> getBar(String id);
/*
* @return the Foo inserted, never empty
*/
abstract Mono<Foo> insertFoo(String id, Foo foo);
/*
* @return the Bar updated, never empty
*/
abstract Mono<Bar> updateBar(Foo foo, Bar bar);
そして、ここで使用して、より複雑な例だTuple2<Foo,Boolean>
オリジナルのFooが見つかった場合(これはあなたの例と意味的に同等でなければなりません)を示すのには:
Mono<Void> updateFoos(Flux<String> idFlux) {
return idFlux // Flux<String>
.flatMap(id -> getFoo(id) // Mono<Foo>
/*
* Map to a Tuple2 whose t2 indicates whether the foo was found.
* In this case, it was found.
*/
.map(foo -> Tuples.of(foo, true)) // Mono<Tuple2<Foo,Boolean>>
/*
* If a Foo with the given id is not found,
* create a new one, and continue the stream with
* a Tuple2 indicating it wasn't originally found
*/
.switchIfEmpty(insertFoo(id, new Foo()) // Mono<Foo>
/*
* Foo was not originally found, so t2=false
*/
.map(foo -> Tuples.of(foo, false))) // Mono<Tuple2<Foo,Boolean>>
/*
* The lambda passed to .flatMap will be
* executed with either:
* A) t1=foo found from getFoo, t2=true
* OR
* B) t1=newly inserted Foo from insertFoo, t2=false
*/
.flatMap(tuple2 -> tuple2.getT2()
// foo originally found
? getBar(tuple2.getT1().bar) // Mono<Bar>
.flatMap(bar -> updateBar(tuple2.getT1(), bar)) // Mono<Bar>
.then() // Mono<Void>
// foo originally not found (new inserted)
: Mono.empty() // Mono<Void>
)
) // Flux<Void>
.then(); // Mono<Void>
}