0
私は妥当性検査を適用するための1つのステップを望むリアクティブストリームを用意しています。それを行うには一般的に受け入れられているスタイルがありますか?私には、then()
、filter()
、およびmap()
に3つのオプション(Mono
を使用)があることがわかります。リアクティブストリームの検証として例外をスローする最も適切な方法
filter()
その中で、私は実際には別のストリームにストリームまたはスイッチ内のデータの種類を変更するつもりはないよ、私が欲しいの流れに最も近いです。しかし、filterはtrue/falseを返して項目をフィルタリングすることになっているので、常にTRUEを返すのは少しばかげている。then()
私は特にエラー/成功の排出を選択できますが、このタイプの検証では、それを自分のプライベートメソッドに分割することができず、ボイラプレートによってストリーム宣言が読みにくくなります。map()
は、filter()
を使用した場合とほとんど同じですが、常にTRUEではなく入力に戻ります。非常に不自然な例として
、人に送信する0文字以上のリストを持ってサービスを考えてみます。このように見えるメソッドを作成するためのより良いオプションは何
public interface Person {
UUID getId();
List<String> getKnownLanguages();
}
public interface Letter {
String getLanguage();
}
public class LetterService {
private Letter findOneLetterForPerson(final UUID id) { /* ... */ }
private void removeLetter(final Letter letter) { /* ... */ }
}
を上記の例で使用
public Mono<Optional<Letter>> getNextValidLetterForPerson(final Person person) {
return Mono.just(person)
.and(this::getNextLetterForPerson)
/////////////////////////////////////////
//
.filter(this::validatePersonCanReadLetter1)
.map(Tuple2::getT2)
//
// OR
//
.then(this::validatePersonCanReadLetter2)
//
// OR
//
.map(this::validatePersonCanReadLetter3)
//
/////////////////////////////////////////
// If the letter was invalid for the person, remove the letter from the
// the system as a side effect, and retry retrieving a letter to send
.doOnError(this::removeInvalidLetter)
.retry(this::ifLetterValidationFailed)
// Map the result to an appropriate Optional
.map(Optional::of)
.defaultIfEmpty(Optional.empty());
}
支持方法は、次のとおり
public static class LetterInvalidException extends RuntimeException {
private Letter mLetter;
public LetterInvalidException(final Letter letter) { mLetter = letter; }
public Letter getLetter() { return mLetter; }
}
/** Gets the next letter for a person, as a reactive stream */
private Mono<Letter> getNextLetterForPerson(final Person person) {
return Mono.create(emitter -> {
final Letter letter = mLetterService.findOneLetterForPerson(person.getId());
if (letter != null) {
emitter.success(letter);
}
else {
emitter.success();
}
});
}
/** Used to check whether the cause of an error was due to an invalid letter */
private boolean ifLetterValidationFailed(final Throwable e) {
return e instanceof LetterInvalidException;
}
/** Used to remove an invalid letter from the system */
private void removeInvalidLetter(final Throwable e) {
if (ifLetterValidationFailed(e)) {
mLetterService.removeLetter(((LetterInvalidException)e).getLetter());
}
}
/*************************************************************************
*
*************************************************************************/
private boolean validatePersonCanReadLetter1(final Tuple2<Person, Letter> tuple) {
final Person person = tuple.getT1();
final Letter letter = tuple.getT2();
if (!person.getKnownLanguages().contains(letter.getLanguage())) {
throw new LetterInvalidException(letter);
}
return true;
}
private Mono<Letter> validatePersonCanReadLetter2(final Tuple2<Person, Letter> tuple) {
return Mono.create(emitter -> {
final Person person = tuple.getT1();
final Letter letter = tuple.getT2();
if (!person.getKnownLanguages().contains(letter.getLanguage())) {
emitter.error(new LetterInvalidException(letter));
}
else {
emitter.success(letter);
}
});
}
private Letter validatePersonCanReadLetter3(final Tuple2<Person, Letter> tuple) {
final Person person = tuple.getT1();
final Letter letter = tuple.getT2();
if (!person.getKnownLanguages().contains(letter.getLanguage())) {
throw new LetterInvalidException(letter);
}
return letter;
}
私はMono<T> validate(..)
のようなメソッドを愛し、ストリームアイテムのテストと例外の返却またはスロー(返された場合、フレームワークはそれをエラーとして処理する)を好むでしょうが、私はむしろリアクティブプログラミングとdidnそのように働くものは何も見ていない。