【问题标题】:How to reduce the usage of IF - ELSE by reflection ? Can I get the code example如何通过反射减少 IF-ELSE 的使用?我可以得到代码示例
【发布时间】:2014-07-04 00:49:33
【问题描述】:

我试图对 PizzaFactory 类的代码使用反射,以便我可以删除 if else 条件并使我的代码更加动态。但我无法弄清楚如何。

   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);   
      }

    }

  }

谁能帮我获得在 PizzaFactory 类中使​​用的反射,以便我可以动态调用 CheesePizza 等类?

【问题讨论】:

  • 看看枚举类型和 switch 语句
  • 我想用反射方法替换 if else。就像我可以动态调用该类一样。我可以只写几行代码,它会检查并调用特定的类。没有 if else ......但使用反射。有可能吗?
  • 为什么 PizzaFactory 扩展 Pizza??只是为了好玩?

标签: java class servlets dynamic reflection


【解决方案1】:

请记住,使用反射解决问题通常会给您带来两个问题 - 使用 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");
}

【讨论】:

  • 这似乎远没有那么可怕。根据程序其余部分的工作方式,可能可以完全删除字符串依赖性并在整个过程中使用枚举
  • @RichardTingle - 仅使用枚举是一个更好的选择。
  • @RichardTingle Tingle 感谢您的宝贵建议。但是不使用 ENUM 而只使用反射就可以达到目的。它也使代码不可怕。
  • @OldCurmudgeon 感谢您的宝贵回答。但是不使用 ENUM 而只使用反射就可以达到目的。它也使代码不可怕。必要时肯定会使用 ENUM。
【解决方案2】:

您可以将 concreate Pizza 的类提供给工厂方法 -

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

【讨论】:

  • 感谢您提供的解决方案,它帮助我得到了答案。
【解决方案3】:

要在减少“if-else”使用方面回答您的问题,您可以动态确定要使用的类,例如而不是

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

你可以使用

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

(以上假设是一个无参数的构造函数)

这将消除任何切换类型的行为。

但是我不会推荐这个。以上是难以调试且不明显的。您的 IDE 可能会将此类类标记为未使用,并且可能会在未来的重构过程中被删除。在绝大多数情况下,我倾向于明确。

简而言之,我宁愿通过 if/else 序列、基于字符串的开关、字符串到方法对象的映射等来指定可用比萨饼的规格,而不是任何复杂的、不明显的、可能是脆弱的机制.

【讨论】:

  • 谢谢!您的回答很简单,我应用了相同的逻辑。现在工作正常。
【解决方案4】:

假设你有你的界面披萨 public interface Pizza { \*some methods *\}

以及public class CheesePizza implements Pizza {}等实现

你可以创建枚举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;
            }
    }
    }

现在你需要做的就是制作新的新鲜披萨

Pizza pizza = PizzaType.Cheese.create();

【讨论】:

    【解决方案5】:

    你可以维护这样一张地图:

    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);
    }
    

    那么,例如:

    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】:

      您将无法避免使用反射条件,否则您的代码将在某些时候失败。但是,根据您的要求,您可以这样做:

      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;
      }
      

      然后,在实施过程中,您可以使用 if 条件检查来确定您想要的披萨类型:

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

      附:我注意到您在包名称中使用了 Camelcase。养成在包中使用小写字母的习惯,如果涉及多个单词,请使用下划线。这只是 Java 约定,虽然不是要求。

      我希望这对你有用。

      【讨论】:

        【解决方案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; 
        
        
             //....
              }
        

        【讨论】:

        • 欢迎来到 SO!请张贴解释为什么你的答案有效,然后提问者/其他人会更好地了解它为什么有效。
        猜你喜欢
        • 1970-01-01
        • 2022-01-22
        • 2022-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-01
        相关资源
        最近更新 更多