【问题标题】:Information hiding and functional programming coding style信息隐藏和函数式编程编码风格
【发布时间】:2017-08-20 00:34:22
【问题描述】:

我正在开发一个名为Simulator 的简单类,它将Simulations 的列表应用于某个输入。对于每个输入,模拟可以产生或不产生输出,这取决于输入对于每个模拟必须满足的某些条件。 Simulator 产生的结果是一个输出列表。

这里是代码。

class Simulator {
    final List<Simulation> simulations;

    // Some initialization code...

    List<Ouput> execute(Input input) {
        return simulations
            .stream()
            .filter(s -> s.processable(input))
            .map(s -> s.prepareOutput(input))
            .collect(Collectors.toList());
    }
}

如您所见,首先我验证输入是否可由Simulation 处理,过滤不能处理的模拟,然后将这些模拟应用于输入。

从面向对象的角度来看,我公开了Simulation 类的内部结构。 processable方法所做的检查操作应该隐藏在prepareOutput方法中。

但是,processableSimulator 可见,我可以应用更实用的方法,这非常方便。

哪种方法更好?我还缺少其他解决方案吗?

【问题讨论】:

  • 如果你认为你在暴露内部,那你为什么要这样做呢?需要考虑的其他一些问题:如果我用someSimulation.prepareOutput(null) 调用您的任何模拟会发生什么?这甚至可以处理吗?或者,如果我使用给定模拟无法处理的输入参数调用prepareOutput,会发生什么?我是否需要从外部了解或检查其可加工性?它是返回null 还是抛出异常? Optional 是一个选项吗?

标签: oop functional-programming java-8 java-stream information-hiding


【解决方案1】:

由于你的类Simulation已经暴露了操作prepareOutput,这可能会失败,所以当你提供方法processable提前检测prepareOutput操作是否会失败时,没有额外的暴露。实际上,提供这样的检查是一个很好的 API 设计,只要预先计算的成本不会太高。

您仍然可以考虑在Simulation提供批量处理操作。

public class Simulation {
    public Output prepareOutput(Input input) {
        …
    }
    public static List<Output> prepareWhenPossible(List<Simulation> list, Input input) {
        return simulations.stream()
            .filter(s -> s.processable(input))
            .map(s -> s.prepareOutput(input))
            .collect(Collectors.toList());
    }
}

重要的是要让调用者清楚它会跳过无法执行操作的元素,而不是实现“全有或全无”的行为。

这仍然不排除公开processable,如果实施起来很便宜的话。这并不是一个不可能的操作,因为总是可以调用prepareOutput 并删除结果以查明该操作是否可行。为此目的使用processable 方法要干净得多。

【讨论】:

  • 我认为您遇到了问题:如果 processable 方法可用于其他类型,那么方法 prepareOutput 在内部调用它很重要。从这个角度来看,prepareOutput 无论如何都应该返回一个Optional&lt;Output&gt;
【解决方案2】:

如果你需要隐藏processable,为什么不做点不一样的:

 Optional<Output> prepareOutput(Input input) {

      boolean isProcessable = processable(input); // processable is private

      if(isProcessable){
            // prepare Output
            return Optional.of(Output);   
      }
      return Optional.empty();

 }

然后是这样的:

  List<Ouput> execute(Input input) {
    return simulations
        .stream()
        .map(s -> s.prepareOutput(input))
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toList());
 }

【讨论】:

  • 但这只是在技术上隐藏processable,而不是在语义上,因为每个人都可以去编写一个方法boolean processable(Simulation s, Input i) { return s.prepareOutput(i).isPresent(); },所以隐藏processable所达到的所有效果,可能会使这个测试效率降低。
  • @Holger 谢谢,好点子。我认为它只是隐藏唯一的方法。加一个用于批量处理的答案..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 2011-08-24
  • 2010-11-08
  • 2016-11-25
相关资源
最近更新 更多