Most of the frameworks and tools you are using right now, are an abstraction of the design patterns and concepts that maybe are more old than you. They introduce you another face of the design pattern, usually intending to hide some complexity.
Today, I want to show you guys what shape (face) takes the decorator pattern when it is implemented with the lambda functionality provided by Java 8. Maybe I think that the key is thinking in the functions like objects.
Let's start. I like so much pizza, specially those days you don't want to cook, which it is quite often.
So you take the phone and call to order a pizza. Your pizza have a price (a base price), for each complement your are adding to your order, the price is increasing.
Take a look to this approach to implement a Order pizza software.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The client orders a Barbacoa pizza. The base price of the pizza is 15 dollars. | |
Pizza myOrder = Pizza.newPizza(15, baicon(), cheese(), tomato(), barbacoaSauce()); | |
// The client adds some complements | |
// We are decorating the pizza with complements | |
myOrder.setComplements( | |
Complements::chips, | |
Complements::extraDrink, | |
Complements::iceCream, | |
Complements::cinemaDisccount); | |
// Finally get the price | |
System.out.println("Base price of the barbacoa pizza: " + myOrder.getBasePrice()); | |
System.out.println("Total price to pay with the complements: " + myOrder.getTotalPrice()); |
Here is the interesting part. Note that the reduce method is combining all the complements in a chain of calls with the method AndThen.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Pizza { | |
private Ingredient[] ingredients; | |
private Function<Pizza, Pizza> complement; | |
private int basePrice; | |
public static Pizza newPizza(int price, Ingredient... ingredients) { | |
return new Pizza(price, ingredients); | |
} | |
private Pizza(int basePrice, Ingredient... ingredients) { | |
this.ingredients = ingredients; | |
this.basePrice = basePrice; | |
} | |
public void setComplements(Function<Pizza, Pizza>... complements) { | |
complement = Stream.of(complements).reduce(Function.identity(), Function::andThen); | |
} | |
public int getTotalPrice() { | |
Pizza p = complement.apply(this); | |
return p.getBasePrice(); | |
} | |
public int getBasePrice() { | |
return basePrice; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static final Ingredient TOMATO = new Ingredient("tomato", 2); | |
private static final Ingredient CHEESE = new Ingredient("cheese", 1); | |
private static final Ingredient EGG = new Ingredient("egg", 3); | |
private static final Ingredient BAICON = new Ingredient("baicon", 5); | |
private static final Ingredient BARBACOA_SAUCE = new Ingredient("barbacoa sauce", 2); | |
public static Ingredient tomato() { | |
return TOMATO; | |
} | |
public static Ingredient baicon() { | |
return BAICON; | |
} | |
public static Ingredient egg() { | |
return EGG; | |
} | |
public static Ingredient cheese() { | |
return CHEESE; | |
} | |
public static Ingredient barbacoaSauce() { | |
return BARBACOA_SAUCE; | |
} |
As you can see this solution has more expressiveness and also avoids the boilerplate code of the traditional way to implement the decorator pattern.
You can find the complete code in my Github profile here
Thank you very much, we keep sharing knowledge.
No comments:
Post a Comment