Question

I was trying to use reflection for the code of PizzaFactory Class so that I can remove the if else condition and make my code more dynamic. But I am not able to figure out how.

   Pizza.java
    package PizzaTrail;
   import java.util.List;

    //this is the main abstract factory which will be extended by the concrete factory 
    public abstract class Pizza {  public abstract List fetchIngredients(String Type); }


    PizzaFactory.java 
   package PizzaTrail;
   import java.util.List;

   //this is the concrete factory 
   public class PizzaFactory extends Pizza
   { 
        public static Pizza getConcretePizza(String PType)
        { 
          Pizza p=null;
          if (PType.equals("Cheese")) 
          {
                     p=new CheesePizza();
          } else if (PType.equals("Pepperoni")) 
          {
              p=new PepperoniPizza();
          }
           else if (PType.equals("Clam")) 
          {
               p = new CalmPizza();

           }
           else if (PType.equals("Veggie")) 
           {
               p= new VeggiePizza();

            }
            return(p); 
       }   
   }


     ChessePizza.java
     package PizzaTrail;

      import java.util.ArrayList;
      import java.util.List;

     public class CheesePizza extends Pizza {
      List ing = new ArrayList();
       @Override
       public List fetchIngredients(String Type)
       {
       ing.add("Ingredient : Shredded Mozzarella Cheese");
      ing.add("Ingredient : Peppers");
      ing.add("Ingredient : Feta cheese");
     ing.add("Ingredient : Pesto");
      return (ing);   
      }

    }

  }

Can anyone help me get the reflection used in the pizzaFactory class so that i can call the class CheesePizza, etc dynamically?

Was it helpful?

Solution 3

To answer your question in terms of reducing 'if-else' usage, you could dynamically determine the class to use e.g. instead of

if (PType.equals("Cheese")) {
    p=new CheesePizza();

you could use

Class.forName(PType + "Pizza").newInstance(); // might need a package

(the above assumes a no-args constructor)

and that would remove any switching-type behaviour.

However I wouldn't recommend this. The above is difficult to debug and non-obvious. Your IDE will likely mark such classes as not being used and a possible candidate for removal during a future refactor. I would favour clarity in the vast majority of cases.

In short, I would much rather specify the specifications of available pizzas via an if/else sequence, a String-based switch, a map of strings to method objects etc. rather than any convoluted, non-obvious, perhaps fragile mechanism.

OTHER TIPS

You could provide the class of the concreate pizza to the factory method -

public static <T extends Pizza> T getConcretePizza(Class<T> clazz) {
    try {
        return clazz.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Bearing in mind that using reflection to solve a problem usually leaves you with two problems - how about using an enum?

enum Pizzas {

    Cheese {

                @Override
                Pizza make() {
                    return new CheesePizza();
                }

            },
    Pepperoni {

                @Override
                Pizza make() {
                    return new PepperoniPizza();
                }

            },
    Clam {

                @Override
                Pizza make() {
                    return new ClamPizza();
                }

            },
    Veggie {

                @Override
                Pizza make() {
                    return new VeggiePizza();
                }

            };

    abstract Pizza make();

    public static Pizza make(String type) {
        return Pizzas.valueOf(type).make();
    }
}

public void test() {
    Pizza pizza = Pizzas.make("Cheese");
}

lets say you have your interface pizza public interface Pizza { \*some methods *\}

and implementations such as public class CheesePizza implements Pizza {}

you could create enum PizzaType

enum PizzaType {
    Cheese(CheesePizza.class);
    Class<?> type;
    PizzaType(Class<?> type) {
        this.type = type;
    }

    Pizza create() {
    try {
        return (Pizza) type.newInstance();
    } catch (Exception e) {
            return null;
            }
    }
    }

now to create new fresh pizza all what you need to do is

Pizza pizza = PizzaType.Cheese.create();

You could maintain such a map:

private static final Map<String, Class<? extends Pizza>> PIZZAS;

static {
    Map<String, Class<? extends Pizza>> pizzas = new HashMap<String, Class<? extends Pizza>>();
    pizzas.put("Cheese", CheesePizza.class);
    pizzas.put("Pepperoni", PepperoniPizza.class);
    PIZZAS = Collections.unmodifiableMap(pizzas);
}

Then, for example:

public static Pizza getConcretePizza(String type) {
    Class<? extends Pizza> clazz = PIZZAS.get(type);
    if (clazz == null) {
        throw new IllegalStateException("No pizza of type " + type);
    }
    try {
        return clazz.newInstance();
    } catch (Exception e) {
        throw new IllegalStateException("Unable to instantiate pizza of type " + clazz.getSimpleName(), e);
    }
}

You will not be able to avoid the use of conditions with reflection, otherwise your code will fail at some point. However, given your request, you can do this:

public static Object getConcretePizza(String type) throws Exception{
    String pizza = String.format("pizza_trail.%sPizza", type);
    Class<?> clazz = Class.forName(pizza);
    Object pizzaClass = clazz.newInstance();

    return pizzaClass;
}

Then, during implementation, you can determine the type of pizza you want using the if condition checks:

Object pizzaObject = PizzaFactory.getConcretePizza("Cheese");
if(pizzaObject instanceof CheesePizza){
    CheesePizza pizza = (CheezePizza) pizzaObject;
    // call CheesePizza related methods here.

}

P.S. I have noticed that you're using Camelcase in your package name. make it a habit of using lowercase letters for packages, and where multiple words are involved, use an underscore. This is just the Java convention, though not a requirement.

I hope this works for you.

      //public static Pizza getConcretePizza(String PType){


      public static Pizza getConcretePizza(Class cType){


     /**
      *

      if (PType.equals("Cheese")) 
      {
                 p=new CheesePizza();
      }//..............  
       */


    Constructor  ctor = cType.getConstructor();
    Object object = ctor.newInstance();
    p = object; 


     //....
      }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top