如何使用Vavr正确实现呢?

时间:2019-01-09 15:43:11

标签: java functional-programming vavr

我想就如何以功能方式正确编写此代码向您提出建议:

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吗?

谢谢

1 个答案:

答案 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>,让您适应您的业务模型。