I am implementing the factory pattern in my code, so came across one interesting thing in factory that I can replace the if else condition in the factory method with Reflection to make my code more dynamic.
Below is the code for both the designs......
1) With if-else conditions
public static Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals(PizzaType.Cheese))
{
pizza = new CheesePizza();
}
else if (type.equals(PizzaType.Tomato))
{
pizza = new TomatoPizza();
}
else if (type.equals(PizzaType.Capsicum))
{
pizza = new CapsicumPizza();
}
else
{
try {
throw new Exception("Entered PizzaType is not Valid");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return pizza;
}
2) With Reflection
public static Pizza createPizza(String type) {
Pizza pizza = null;
for(PizzaType value : PizzaType.values())
{
if(type.equals(value.getPizzaTypeValue()))
{
String fullyQualifiedclassname = value.getClassNameByPizzaType(type);
try {
pizza = (Pizza)Class.forName(fullyQualifiedclassname).newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return pizza;
}
Second way looks very good to me as I can make my code more dynamic by using it, as I can create one property file with the names of classes and type associated with it to serve the Open and close a bit more, as if in future owners wants to add more pizzas to PizzaStore then he would just make the entry in the property file and will just create one more subclass of Pizza.
But I read that reflection has many disadvantages mentioned few of them.
It is hack of compiler
Automatic development tools are not able to work with reflections code
It's difficult to debug reflections code
Reflection complicates understanding and navigation in code
Significant performance penalty
So very curious to know that, which design is good, as I am very interested to make my code more and more dynamic.
You can also use a design in the middle. E.g.
public interface Factory<T> {
public T newInstance();
}
public class TomatoPizzaFactory implements Factory<TomatoPizza> {
@Override
public TomatoPizza newInstance() {
return new TomatoPizza();
}
}
public class PizzaFactory {
private Map<String, Factory<? extends Pizza>> factories = new HashMap<String, Factory<? extends Pizza>>();
public PizzaFactory(){
factories.put(PizzaType.Cheese, new CheesePizzaFactory());
factories.put(PizzaType.Tomato, new TomatoPizzaFactory());
}
public Pizza createPizza(String type){
Factory<? extends Pizza> factory = factories.get(type);
if(factory == null){
throw new IllegalArgumentException("Unknown pizza type");
}
return factory.newInstance();
}
}
Implement a DefaultConstructorFactory for simple instantiations.
public class DefaultConstructorFactory<T> implements Factory<T> {
private Class<T> type;
public DefaultConstructorFactory(Class<T> type) {
this.type = type;
}
public T newInstance() {
try {
return type.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Can not instantiate " + type, e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Can not instantiate " + type, e);
}
}
}
But I read that reflection has many disadvantages mentioned few of them.
It is hack of compiler
It can be a hack, but if you are writing infrastructure code you will often use reflections. Especially when you write frameworks that must introspect classes at runtime, because the framework doesn't know the classes it will handle at runtime. Think about hibernate, spring, jpa, etc.
Automatic development tools are not able to work with reflections code
That's true, because you shift a lot of compiler issues to runtime. So you should handle reflection exceptions like a compiler and provide good error messages.
There is also only a little refactoring support in some IDEs. So you must be careful when changing code used by reflection code.
Nevertheless you can write tests to find bugs fast.
It's difficult to debug reflections code
That's also true, because you can't jump into a method directly and you have to investigate the variables to find out which member of which object is accessed. It is a bit more indirection.
Reflection complicates understanding and navigation in code
Yes, if it is used the wrong way. Only use reflection if you do not know the types you have to handle at runtime (infrastructure or framework code). Don't use reflection if you know the types and you only want to minimize code written. If you want to minimize code written select a better design.
Significant performance penalty
I don't think so. Of course reflection calls are indirect method invokations and thus more code must be executed in order to do the same as a direct method call. But the overhead for this is minimal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With