I have a program that can print a pizza with decorators. I have an interface:
public interface PizzaPie{
String top();
}
And an implementation of the interface
public class PizzaPieImplementation implements PizzaPie{
@Override
public String top() {
return "Pie of pizza";
}
}
And an abstract class that implements it with the same object.
public abstract class PizzaTopper implements PizzaPie{
private PizzaPie pizza;
@Override
public String top() {
return pizza.top();
}
}
And I have several decorator classes, such as
public class Onions extends PizzaTopper{
public Onions(PizzaPie pizza) {
super(pizza);
}
public String top() {
return super.top() + topWithOnions();
}
private String topWithOnions() {
return " with onions";
}
And similar classes for peppers, pepperoni, anchovies, pineapple, etc.
I have a list as follows:
List<String> toppings = {onions, pineapple};
Is there a way to take each topping from the toppings list, and use that to create a new pizza with those toppings, to return something like:
Pie of pizza with onions with pineapple
The method would look something like this:
public PizzaPie CreatePizzaWithUserInput(List<String> toppings) {
//code
}
And ultimately it would create code that looks like this:
PizzaPie pizza1 = new Onion(new Pineapple(new PizzaPieImplementation()));
In theory this can be done with a lot of ugly if statements but I'm wondering if there's a quicker way of doing it.
You can use Java Reflection to achieve this.
Here we build our factory with the different possibilities of toppings, then we create a Pizza using createPizzaWithUserInput
.
In this example we built a pizza with 3 of the four possible toppings.
Notice that to add a new Topping possibility you just extends PizzaTopper
and add it on the toppingOptions on the PizzaFactory
instantiation.
import java.util.List;
import java.util.LinkedList;
class Main {
public static void main(String[] args) {
// Possibilities
PizzaFactory pizzaFactory = new PizzaFactory(Onions.class, Bacon.class, Olives.class, Tomatos.class);
// User input
List<String> toppings = new LinkedList<String>();
toppings.add("onions");
toppings.add("olives");
toppings.add("bacon");
try{
PizzaPie pizza = pizzaFactory.createPizzaWithUserInput(toppings);
System.out.println(pizza.top());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here we have the PizzaFactory. We use the class' name to do the matching with the topping option, but you can customize it if you want (to match also "onion"/"onions" or "tomato"/"tomatos" for instance).
import java.util.List;
import java.util.Arrays;
import java.lang.reflect.*;
public class PizzaFactory {
List<Class<? extends PizzaTopper>> toppingOptions;
public PizzaFactory(Class<? extends PizzaTopper>... toppingOptions) {
this.toppingOptions = Arrays.asList(toppingOptions);
}
public PizzaPie createPizzaWithUserInput(List<String> toppings) throws NoSuchMethodException, InstantiationException, IllegalAccessException,InvocationTargetException {
PizzaPie pizza = new PizzaPieImplementation();
for(String toppingName : toppings) {
for(Class<? extends PizzaTopper> top : toppingOptions) {
if(top.getName().toLowerCase().equals(toppingName.toLowerCase())) {
Constructor<? extends PizzaPie> constructor = top.getConstructor(PizzaPie.class);
pizza = constructor.newInstance(pizza);
}
}
}
return pizza;
}
}
Here we have the interface PizzaPie:
public interface PizzaPie{
String top();
}
And its implementation.
public class PizzaPieImplementation implements PizzaPie{
@Override
public String top() {
return "Pie of pizza";
}
}
The decorator class.
public abstract class PizzaTopper implements PizzaPie{
private PizzaPie pizza;
protected PizzaTopper(PizzaPie pizza) {
this.pizza = pizza;
}
@Override
public String top() {
return pizza.top();
}
}
Tomatos topping.
public class Tomatos extends PizzaTopper{
public Tomatos(PizzaPie pizza) {
super(pizza);
}
public String top() {
return super.top() + topWithOnions();
}
private String topWithOnions() {
return " with tomatos";
}
}
Onions topping.
public class Onions extends PizzaTopper{
public Onions(PizzaPie pizza) {
super(pizza);
}
public String top() {
return super.top() + topWithOnions();
}
private String topWithOnions() {
return " with onions";
}
}
Olives topping
public class Olives extends PizzaTopper{
public Olives(PizzaPie pizza) {
super(pizza);
}
public String top() {
return super.top() + topWithOnions();
}
private String topWithOnions() {
return " with olives";
}
}
Bacon topping.
public class Bacon extends PizzaTopper{
public Bacon(PizzaPie pizza) {
super(pizza);
}
public String top() {
return super.top() + topWithOnions();
}
private String topWithOnions() {
return " with bacon";
}
}