我想就如何以功能方式正确编写此代码向您提出建议:
private Option<CalcResult> calculate(Integer X, Integer Y) {
if (X < Y) return Option.none();
return Option.of( X + Y );
}
public Option<CalcResult> otherMethod(Obj o) {
if (o.getAttr()) {
// getA() & getB() are APIs out of my control and could return a null value
if (o.getA() != null && o.getB() != null) {
return calculate(o.getA(), o.getB());
}
}
return Option.none();
}
计算很简单:
private Option<CalcResult> calculate(Integer X, Integer Y) {
return Option.when(X > Y, () -> X + Y);
}
对于otherMethod
,这是我的第一种方法:
public Option<CalcResult> otherMethod(Obj o) {
return Option.when(o.getAttr(), () ->
For(Option.of(o.getA()), Option.of(o.getB()))
.yield(this::calculate)
.toOption()
.flatMap(Function.identity())
).flatMap(Function.identity());
}
但是,与第一个版本相比,我觉得代码的可读性不如我期望的那样(双flatMap
让人一眼就很难理解为什么会出现)
我尝试了另一种方法,从而改善了讲课:
public Option<CalcResult> otherMethod(Obj o) {
return For(
Option.when(o.getAttr(), o::getAttr()),
Option.of(o.getA()),
Option.of(o.getB()))
.yield((__, x, y) -> this.calculate(x, y))
.toOption()
.flatMap(Function.identity());
}
这种方式更具可读性,但是我认为我在这种情况下无法正确理解。
您对此案有何建议?我可以正确使用vavr的API吗?
谢谢
答案 0 :(得分:1)
我将完全按照您的方式编写calculate
(除非我永远不会对参数:P使用大写字母。)
对于otherMethod
,我将使用模式匹配。 Vavr中的模式匹配在Haskell之类的功能更强的语言中甚至还不接近PM,但是我认为它仍然正确地代表了您的意图:
public Option<Integer> otherMethod(Obj o) {
return Option.when(o.getAttr(), () -> Tuple(Option(o.getA()), Option(o.getB()))) //Option<Tuple2<Option<Integer>, Option<Integer>>>
.flatMap(ab -> Match(ab).option( // ab is a Tuple2<Option<Integer>, Option<Integer>>
Case($Tuple2($Some($()), $Some($())), () -> calculate(o.getA(), o.getB())) // Read this as "If the pair (A, B)" has the shape of 2 non-empty options, then calculate with what's inside
// Result of Match().option() is a Option<Option<Integer>>
).flatMap(identity())); // Option<Integer>
}
替代方法,不带注释(请注意,我们使用Match().of()
代替Match().option()
,因此我们必须处理所有可能的形状):
public Option<Integer> otherMethod(Obj o) {
return Option.when(o.getAttr(), () -> Tuple(Option(o.getA()), Option(o.getB())))
.flatMap(ab -> Match(ab).of(
Case($Tuple2($Some($()), $Some($())), () -> calculate(o.getA(), o.getB())),
Case($(), () -> None())
));
}
我将CalcResult
替换为Integer
,因为在您的示例中,calculate
确实返回了Option<Integer>
,让您适应您的业务模型。