Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Information hiding and functional programming coding style

I was developing a simple class, called Simulator, that applies a list of Simulations 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?

like image 525
riccardo.cardin Avatar asked Aug 31 '26 17:08

riccardo.cardin


2 Answers

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.

like image 184
Holger Avatar answered Sep 02 '26 07:09

Holger


If you need to hide processable, why not do it a bit different:

 Optional<Output> prepareOutput(Input input) {

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

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

 }

And then something like this:

  List<Ouput> execute(Input input) {
    return simulations
        .stream()
        .map(s -> s.prepareOutput(input))
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toList());
 }
like image 40
Eugene Avatar answered Sep 02 '26 07:09

Eugene



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!