可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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.
回答2:
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");
}
回答3:
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);
}
}
回答4:
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();
回答5:
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);
}
}
回答6:
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.
回答7:
//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;
//....
}