-2

How can you apply to this OOP java code a more functional style?

class PaintCarCost
  Car car;
  Paint paint;
  PaintMaterialsMixture mixture;

  double cost () {
    double volumeToPaint = ... // calculate from car and mixture
    double necessaryVolumePaint = ... // calculate from volumeToPaint, car and paint
    double necessaryKgPaint = ... // calculate from necessaryVolumePaint and paint
    double cost = ... // calculate from necessaryKgPaint and paint
    return cost;
  }
}

I had thought split each calculation in a function:

private BiFunction <Car,PaintMaterialsMixture,Double> volumeToPaint = ...
private BiFunction <Double,Car,Paint> necessaryVolumePaint = ...
private BiFunction <Double,Paint> necessaryKgPaint = ...

but I don't know how chain all of them in an elegant way to make the final cost. Each function have to take into account the last result, but I need to pass different arguments in each function too.

user1151816
  • 187
  • 4
  • 13
  • Perhaps you could use method-chaining. – achAmháin Jul 03 '18 at 11:05
  • You can use `Function#andThen` – Lino Jul 03 '18 at 11:06
  • 5
    I don't see any advantages pressing this in a functional style. Moving individual steps into own methods and chaining these methods would be more than enough. Why do you want functional style here? – lexicore Jul 03 '18 at 11:07
  • It is a good practice to explain in comments if you downvote, so that OP as well as other readers can benefit from your worthy opinion. – Asad Iqbal Aug 21 '18 at 14:18

2 Answers2

1

In functional programming, you think in terms of functions (input / output relation) instead of algorithms (computation steps). You avoid side effects and state.

So instead of having a stateful PaintCarCost object, you have a stateless PaintCarCost function:

class PaintCarCost
  double cost (Car car, Paint paint, PaintMaterialsMixture mixture) {
    double volumeToPaint = ... // calculate from car and mixture
    double necessaryVolumePaint = ... // calculate from volumeToPaint, car and paint
    double necessaryKgPaint = ... // calculate from necessaryVolumePaint and paint
    double cost = ... // calculate from necessaryKgPaint and paint
    return cost;
  }
}

In my opinion, local variables are fine, of course you can always split functions into smaller functions (and should), but the real issue here in my opinion is the state you should avoid.

kutschkem
  • 7,826
  • 3
  • 21
  • 56
  • 2
    might as well make the function `static` as you removed any state from it – Lino Jul 03 '18 at 11:13
  • @Lino Sure but there might be reasons not to - depending on how this is used, one could have a subclass provide a different implementation of the cost function. – kutschkem Jul 03 '18 at 11:15
1

Each function have to take into account the last result, but I need to pass different arguments in each function too.

You may be looking for currying

Currying is when you break down a function that takes multiple arguments into a series of functions that take part of the arguments.

In , this will normally look like using some arguments to create a new object, which includes an interface to take the remaining arguments. (In more recent versions of Java, you are more likely to see lambda's used, but the basic idea is the same.)

double volumeToPaint = ... // calculate from car and mixture
double necessaryVolumePaint = ... // calculate from volumeToPaint, car and paint
double necessaryKgPaint = ... // calculate from necessaryVolumePaint and paint
double cost = ... // calculate from necessaryKgPaint and paint
return cost;

So in this example, we want to build a bunch of functions that accept a double as an argument, and return a double as a result, that will all get chained together.

DoubleUnaryOperator computeNecessaryVolume = someFactory.createComputeNecessaryVolume(car, paint);
DoubleUnaryOperator computeNecessaryKgPaint = someFactory.createComputeNecessaryKgPaint(paint);
DoubleUnaryOperator computeCost = someFactory.createComputeCost(paint);

double volumeToPaint = computeVolume(car, mixture);
double necessaryVolumeToPaint = computeNecessaryVolume.applyAsDouble(volumeToPaint);
double necessaryKgPaint = computeNecessaryKgPaint.applyAsDouble(necessaryVolumeToPaint);
double cost = computeCost.applyAsDouble(necessaryKgPaint);

That's the basic idea; you can possibly "simplify" it by then chaining the functions together into a pipeline, as we might do with a stream....

cost = computeVolume(car, mixture)
.map(volumeToPaint -> computeNecessaryVolume.applyAsDouble(volumeToPaint))
.map(necessaryVolumeToPaint -> computeNecessaryKgPaint.applyAsDouble(necessaryVolumeToPaint))
.map(necessaryKgPaint -> computeCost.applyAsDouble(necessaryKgPaint) )

But more likely you would just compose the functions together.

DoubleUnaryOperation doIt = computeNecessaryVolume
                            .andThen(computeNecessaryKgPaint) 
                            .andThen(computeCost);

double cost = doIt.applyAsDouble(computeVolume(car, mixture))

Can you write some example about function declaration of computeNecessaryVolume, computeNecessaryKgPaint and computeCost functions?

class ComputeNecessaryVolume implements DoubleUnaryOperator {
    final Car car;
    final Mixture mixture;

    ComputeNecessaryVolume(Car car, Mixture mixture) {
        this.car = car;
        this.mixture = mixture;
    }

    @Override
    double applyAsDouble(double volumeToPaint) {
        // Do whatever you were doing before with car, mixture, and volumeToPaint
        double necessaryVolumeToPaint = ...

        return necessaryVolumeToPaint;
    }
}
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • This was my first idea... declare functions and chaining with andThen methods, but the problem is that I need to pass different type of arguments in each function and I don't know how do it? Can you write some example about function declaration of computeNecessaryVolume, computeNecessaryKgPaint and computeCost functions? – user1151816 Jul 03 '18 at 13:18