jeudi 28 juillet 2016

Decorator pattern using Java 8

Wikipedia has an example of a decorator pattern here:

http://ift.tt/1U7sg1Q

I was trying to solve this using functional style using Java 8,the solution I came up:

1.CoffeeDecorator.java

public class CoffeeDecorator {

public static Coffee getCoffee(Coffee basicCoffee, Function<Coffee, Coffee>... coffeeIngredients) {

    Function<Coffee, Coffee> chainOfFunctions = Stream.of(coffeeIngredients)
                                                      .reduce(Function.identity(),Function::andThen);
    return chainOfFunctions.apply(basicCoffee);
}

public static void main(String args[]) {

    Coffee simpleCoffee = new SimpleCoffee();
    printInfo(simpleCoffee);

    Coffee coffeeWithMilk = CoffeeDecorator.getCoffee(simpleCoffee, CoffeeIngredientCalculator::withMilk);
    printInfo(coffeeWithMilk);

    Coffee coffeeWithWSprinkle = CoffeeDecorator.getCoffee(coffeeWithMilk,CoffeeIngredientCalculator::withSprinkles);       
    printInfo(coffeeWithWSprinkle);

}

public static void printInfo(Coffee c) {
    System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
}

}

2.CoffeeIngredientCalculator.java

public class CoffeeIngredientCalculator {

public static Coffee withMilk(Coffee coffee) {
    return new Coffee() {

        @Override
        public double getCost() {
            return coffee.getCost() + 0.5;
        }

        @Override
        public String getIngredients() {
            return coffee.getIngredients() + " , Milk";
        }
    };
}

public static Coffee withSprinkles(Coffee coffee) {
    return new Coffee() {

        @Override
        public double getCost() {
            return coffee.getCost() + 0.2;
        }

        @Override
        public String getIngredients() {
            return coffee.getIngredients() + " , Sprinkles";
        }
    };
}

}

Now, I am not so convinced with the solution in the CoffeeIngredientCalculator. If we had a single responsibility in the Coffee interface, getCost(), using the functional style and applying the decorator pattern seems a lot better and cleaner. It would basically boil down to a Function<Double,Double> ,we would not need the abstract class, separate decorators and can just chain the functions.

But in the coffee example, with 2 behaviors of the cost and description on the Coffee object, I am not so convinced that this is a significant value addition as we are creating an anonymous class,overriding the 2 methods.

Questions:

1) Is this solution acceptable ?

2) If not, is there a better way to solve it using functional style?

3) Should we stick to the usual GOF way of having an abstract class and separate decorator classes in scenarios where the object that we are decorating has multiple methods?

Aucun commentaire:

Enregistrer un commentaire