Oop 信息隐藏与函数式编程编码风格

Oop 信息隐藏与函数式编程编码风格,oop,functional-programming,java-8,java-stream,information-hiding,Oop,Functional Programming,Java 8,Java Stream,Information Hiding,我正在开发一个简单的类,名为Simulator,它将Simulation列表应用于特定的输入。对于每个输入,模拟可以产生输出,也可以不产生输出,这取决于输入必须满足的与每个模拟相关的一些条件。模拟器产生的结果是一个输出列表 这是代码 class Simulator { final List<Simulation> simulations; // Some initialization code... List<Ouput> execute(In

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

这是代码

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());
    }
}
类模拟器{
最终清单模拟;
//一些初始化代码。。。
列表执行(输入){
返回模拟
.stream()
.filter(s->s.可处理(输入))
.map(s->s.prepareOutput(输入))
.collect(Collectors.toList());
}
}
如您所见,首先,我验证输入是否可由
模拟处理,过滤不可处理的模拟,然后将这些模拟应用于输入

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

但是,由于
模拟器
可以看到
可处理的
,我可以应用一种功能更强大的方法,这非常方便


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

如果需要隐藏可处理的
,为什么不做一些不同的事情:

 Optional<Output> prepareOutput(Input input) {

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

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

 }
可选准备输出(输入){
布尔值isProcessible=可处理(输入);//可处理是私有的
if(可处理){
//准备输出
返回可选。of(输出);
}
返回可选的.empty();
}
然后像这样:

  List<Ouput> execute(Input input) {
    return simulations
        .stream()
        .map(s -> s.prepareOutput(input))
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toList());
 }
列表执行(输入){
返回模拟
.stream()
.map(s->s.prepareOutput(输入))
.filter(可选::isPresent)
.map(可选::get)
.collect(Collectors.toList());
}

由于您的类
模拟
已公开操作
prepareOutput
,该操作可能会失败,因此当您提供方法
可处理
以提前检测
prepareOutput
操作是否会失败时,没有额外的公开。事实上,提供这样的检查是一种很好的API设计,只要事先计算不会太昂贵

您仍然可以考虑在<代码>模拟< /代码>类中提供批量处理操作。

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());
    }
}
公共类模拟{
公共输出准备输出(输入){
…
}
公共静态列表准备(列表列表,输入){
return.stream()
.filter(s->s.可处理(输入))
.map(s->s.prepareOutput(输入))
.collect(Collectors.toList());
}
}
重要的是要让调用者清楚地知道,它将跳过不可能执行操作的元素,而不是实现“要么全有,要么全无”的行为


这仍然不排除公开可处理的
,如果实现起来很便宜的话。这并不是说这是一个不可能的操作,因为总是可以调用
prepareOutput
并删除结果以确定该操作是否可能。有一个
可处理的
方法来实现这个目的要干净得多。

如果你认为你是在暴露内部,那么为什么要这样做呢?需要思考的其他一些问题:如果我使用
someSimulation.prepareOutput(null)
调用您的任何模拟,会发生什么?这是可以处理的吗?或者,如果我使用给定模拟无法处理的输入参数调用
prepareOutput
,会发生什么?我是否需要从外部了解或检查其加工性能?它是返回
null
还是抛出异常?
是可选的吗
是一个选项吗?但这只是在技术上隐藏了
可处理的
,而不是在语义上,因为每个人都可以去写一个方法
布尔可处理的(模拟s,输入i){返回s.prepareOutput(i).isPresent();}
,所以隐藏
可处理的
实现了,这可能会降低测试的效率。@Holger谢谢你,说得好。我以为这只是为了隐藏唯一的方法。对于批量处理,您的答案还有一个。我认为您遇到了问题:如果
processable
方法可用于其他类型,那么方法
prepareOutput
在内部调用它是很重要的。在此透视图下,
prepareOutput
无论如何都应该返回一个
可选的