I was developing a simple class, called Simulator
, that applies a list of Simulation
s to a certain input. For each input the simulations can produce an output or not, based on some conditions that the input has to fulfill with respect to each simulation. The result produced by the Simulator
is a list of output.
Here is the code.
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());
}
}
As you can see, first I verify if an input is processable by a Simulation
, filtering the simulations for which it is not, and then applying these simulations to the input.
From a object oriented point of view, I am exposing internals of Simulation
class. The check operation done by the processable
method should be hide inside the prepareOutput
method.
However, having processable
visible to Simulator
, I can apply a more functional approach, which is very convenient.
Which approach is better? Is there any other solutions I am missing?
Since your class Simulation
is already exposing the operation prepareOutput
, which can fail, there is no additional exposure when you offer the method processable
to detect in advance, whether the prepareOutput
operation would fail. Actually, it is a good API design to offer such a check, as long as it isn’t too expensive to calculate in advance.
You may still consider offering the bulk processing operation within the Simulation
class.
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());
}
}
It’s important to make it clear to the caller that it will skip elements for which the operation isn’t possible, instead of implementing an “all or nothing” behavior.
This still doesn’t preclude exposing processable
, if it is cheap to implement. It isn’t as if this was an otherwise impossible operation, as it is always possible to just call prepareOutput
and drop the result to find out whether the operation is possible. Having a processable
method for that purpose is much cleaner.