Я пытаюсь научиться реактивному программированию путем рефакторинга некоторого в настоящее время блокирующего кода. Я неоднократно сталкивался с проблемой установки состояния некоторого изменяемого объекта данных из последовательности Mono
без подписки на нее. В старом коде значения полей объекта вычислялись неким блокирующим сервисом, который я сейчас также делаю внутри Mono
s.
До сих пор я обычно (ab) использовал flatMap
для получения ожидаемогоПоведение:
initExpensiveObject().flatMap(expObj -> initExpensiveField(expObj).map(expField -> {
expObj.setExpensiveField(expField);
return expObj;
})).subscribe(expObj -> System.out.println("expensiveField: " + expObj.getExpensiveField()));
import reactor.core.publisher.Mono;
public class Main {
/**
* Expensive, lazy object instantiation
*/
public static Mono<ExpensiveObject> initExpensiveObject() {
return Mono.fromCallable(ExpensiveObject::new);
}
/**
* Expensive, async mapping (i.e. database access, network request):
* ExpensiveObject -> int
*/
public static Mono<Integer> initExpensiveField(ExpensiveObject expObj) {
return Mono.just(1);
}
public static class ExpensiveObject {
private int expensiveField = -1;
public int getExpensiveField() {
return expensiveField;
}
public void setExpensiveField(int expensiveField) {
this.expensiveField = expensiveField;
}
}
}
Хотя этот flatMap
-паттерн работает, я чувствую, что должно быть более реактивное решение. Учитывая, что в одном Mono
столько операторов, интуитивно кажется неправильным «отображать» один объект на один и тот же, чтобы изменить его состояние. Операторы «побочного эффекта» (doOn*
), однако, не позволяют легко трансформировать другого издателя без подписки на него.
Я очень открыт для улучшений дизайна, если нет тривиального решенияк моей проблеме, потому что дизайн кода по-прежнему последовательный .