多个 If-else 或枚举 - 哪一个更可取,为什么?[已关闭]

2022-09-03 16:23:24

以下是原始代码:

public class FruitGrower {
    public void growAFruit(String type) {
        if ("wtrmln".equals(type)) {
            //do watermelon growing stuff
        } else if ("ppl".equals(type)) {
            //do apple growing stuff
        } else if ("pnppl".equals(type)) {
            //do pineapple growing stuff
        } else if ("rng".equals(type)) {
            //do orange growing stuff
        } else {
            // do other fruit growing stuff
        }
    }
}

这就是我如何改变它:

public class FruitGrower {
    enum Fruits {
        WATERMELON {
            @Override
            void growAFruit() {
                //do watermelon growing stuff
            }
        },

        APPLE {
            @Override
            void growAFruit() {
                //do apple growing stuff
            }
        },

        PINEAPPLE {
            @Override
            void growAFruit() {
                //do pineapple growing stuff
            }
        },

        ORANGE {
            @Override
            void growAFruit() {
                //do orange growing stuff
            }
        },

        OTHER {
            @Override
            void growAFruit() {
                // do other fruit growing stuff
            }
        };
        static void grow(String type) {
            if ("wtrmln".equals(type)) {
                WATERMELON.growAFruit();
            } else if ("ppl".equals(type)) {
                APPLE.growAFruit();
            } else if ("pnppl".equals(type)) {
                PINEAPPLE.growAFruit();
            } else if ("rng".equals(type)) {
                ORANGE.growAFruit();
            } else {
                OTHER.growAFruit();
            }
        };
        abstract void growAFruit();
    }

    
    public void growAFruit(String type) {
        Fruits.grow(type);
    }
}

我看到代码更长,可能不如代码清晰,但我相信它更好,有人可以告诉我,为什么我错了(或者也许我不是)?enumsif-else

对于使用枚举而不是 if-else 是否有任何顾虑?


答案 1

您已经得到了有关改进枚举使用的好答案。至于为什么它们比字符串常量更好:

我认为最大的好处是编译时错误检查。如果我调用 ,编译器不会知道有什么问题。由于我已经正确拼写了它,因此当您查看代码时,它不会成为一个错误。但是,如果我这样做,编译器可以立即告诉您我拼错了它。growAFruit("watermelon")WATERMELEN.growAFruit()

您还可以定义为一堆简单,易于阅读的方法,而不是一大块--s。当你有几十个水果,或者当你开始添加、、等时,这一点变得更加明显。如果没有枚举,你就会复制你的大if-else块,如果你忘记添加一个案例,它会落入默认案例或什么都不做,而使用枚举,编译器可以告诉你该方法尚未实现。growAFruitifthenelseharvestAFruit()packageAFruit()sellAFruit()

更多的编译器检查优点:如果您还有一个方法和相关字符串常量,则没有什么可以阻止您调用 或 .如果你有一个常量,知道你是认为它是水果还是蔬菜的唯一方法是阅读相关方法的源代码。再一次,通过枚举,编译器可以立即告诉您是否做错了什么。growVegetablegrowVegetable("pineapple")growFruit("peas")"tomato"

另一个好处是,它将相关的常量组合在一起,并给它们一个合适的家。另一种选择是在某个碰巧使用它们的类中抛出一堆字段,或者卡住一个常量接口。充满常量的接口甚至没有意义,因为如果这就是你所需要的,那么定义枚举比写出接口要容易得多。此外,在类或接口中,可能会意外地对多个常量使用相同的值。public static final

它们也是可迭代的。要获得枚举的所有值,您只需调用 ,而使用常量,您必须创建并填充自己的数组。或者,如果只使用文本(如示例中所示),则没有有效值的权威列表Fruit.values()

奖金回合:IDE 支持

  • 通过枚举,您可以使用 IDE 的自动完成功能和自动重构
  • 你可以在Eclipse中使用诸如“查找引用”之类的东西和枚举值,而你必须做一个纯文本搜索来查找字符串文本,这通常也会返回很多误报(如果你使用静态的最终常量,有人可能会在某个地方使用字符串文本)

不使用枚举的主要原因是,如果您在编译时不知道所有可能的值(即,您需要在程序运行时添加更多值)。在这种情况下,您可能希望将它们定义为类继承。另外,不要将一堆不相关的常量放入枚举中并称之为一天。应该有某种公共线程连接这些值。如果更合适,您始终可以创建多个枚举。


答案 2

枚举是要走的路,但你可以像这样大幅改进你的代码:

public static String grow(String type) {
    return Fruits.valueOf(type.toUpperCase()).gimmeFruit();
};

哦,你需要一个默认的情况,这使得它有点困难。当然,你可以这样做:

public static String grow(String type) {
    try{
        return Fruits.valueOf(type.toUpperCase()).gimmeFruit();
    }catch(IllegalArgumentException e){
        return Fruits.OTHER.gimmeFruit();
    }
};

但那是相当丑陋的。我想我会像这样:

public static String grow(String type) {
    Fruits /*btw enums should be singular */ fruit = Fruits.OTHER;
    for(Fruits candidate : Fruits.values()){
        if(candidate.name().equalsIgnoreCase(type)){
            fruit = candidate;
            break;
        }
    }
    return fruit.gimmeFruit();
};

此外,如果枚举方法所做的只是返回一个值,则应重构设计,以便在构造函数中初始化值,并在 Enum 类中定义的方法中返回它们,而不是单个项:

public enum Fruit{
    WATERMELON("watermelon fruit"),
    APPLE("apple fruit")
    // etc.

    ;
    private final String innerName;
    private Fruit(String innerName){ this.innerName = innerName; }
    public String getInnerName(){ return this.innerName; }
}