Тьфу.Несколько вещей, которые мне не нравятся в этом фрагменте, но я начну с большого - вложения.
Единственная причина вложения заключается в том, что в (например) expensiveOp5()
вам нуженссылка на d1
, d2
и d3
, а не просто d4
- так что вы не можете просто отобразить "нормально", потому что вы потеряете эти более ранние ссылки.Иногда возможно рефакторинг этих зависимостей в определенном контексте, поэтому я сначала изучу этот маршрут.
Однако, если это невозможно или нежелательно, я склонен находить глубоко вложенные flatMap()
вызовы, такие какэто лучше всего заменить промежуточными объектами через композицию.
Если у вас есть несколько классов, например, таких как:
@Data
class IntermediateResult1 {
private DataType1 d1;
private DataType2 d2;
}
@Data
class IntermediateResult2 {
public IntermediateResult2(IntermediateResult1 i1, DataType3 d3) {
this.d1 = i1.getD1();
this.d2 = i1.getD2();
this.d3 = d3;
}
private DataType1 d1;
private DataType2 d2;
private DataType3 d3;
}
... и так далее, тогда вы можете просто сделать что-токак:
return d1.flatMap(d1 -> new IntermediateResult1(d1, service.expensiveOp2(d1.foo())))
.flatMap(i1 -> new IntermediateResult2(i1, service.expensiveOp3(i1.getD1().bar(), i1.getD2().baz())))
//etc.
Конечно, вы также можете затем разбить вызовы на их собственные методы, чтобы сделать его более понятным (что я, вероятно, посоветует в этом случае):
return d1.flatMap(this::doOp1)
.flatMap(this::doOp2)
.flatMap(this::doOp3)
.flatMap(this::doOp4)
.flatMap(this::doOp5);
Очевидно, что имена, которые я использовал выше, следует рассматривать только как заполнители - вы должны тщательно обдумать эти имена, поскольку хорошее именование здесь сделает рассуждения и объяснения реактивного потока гораздо более естественными.
ПомимоВложенность, два других момента, которые стоит отметить в этом коде:
- Используйте
return Mono.error(new ConflictException("Already active"));
вместо того, чтобы бросать явно, так как это сильноБолее того, вы имеете дело с явным Mono.error
в потоке. - Никогда не использует изменяемые методы, такие как
setStatus()
на полпути через реактивную цепочку, - это требует проблем позже.Вместо этого используйте что-то вроде with
pattern , чтобы сгенерировать новый экземпляр d2
с обновленным полем.Затем вы можете позвонить по номеру expensiveOp5(d1, d2.withStatus(Status.ACTIVE), d3)
, лишившись этого звонка сеттера.