多个If-else或枚举 - 哪一个更好,为什么?

dhb*_*lah 15 java enums if-statement code-design

这是原始代码:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我改变它的方式:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到enums代码更长,可能不像if-else代码那么清晰,但我相信它更好,有人能告诉我,为什么我错了(或者我不是)?

UPD - 更改了源代码以更具体问题.我将重新解释一下这个问题:是否有关于使用枚举而不是if-else的问题?

Bra*_*ace 18

您已经获得了有关改进Enums使用的良好答案.至于为什么它们比字符串常量更好:

我认为最大的好处是编译时错误检查.如果我打电话growAFruit("watermelon"),编译器就不知道出了什么问题.因为我拼写正确,所以当你查看代码时,它不会被证明是一个错误.但是,如果我这样做WATERMELEN.growAFruit(),编译器可以立即告诉你我拼错了它.

您还可以定义growAFruit为一串简单,易于阅读的方法,而不是一大块if- then- else秒.当你有几十个水果,或当你开始增加,这变得更加明显harvestAFruit(),packageAFruit(),sellAFruit(),等不枚举你会复制你的大的if-else块一切都过去了,如果你忘了添加的情况下,它会下降通过默认情况或什么都不做,而使用枚举编译器可以告诉你该方法尚未实现.

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

另一个好处是它将相关的常数组合在一起并为它们提供了一个合适的家.另一种选择是public static final在一些类中抛出的一堆字段碰巧使用它们,或者插入常量接口.充满常量的接口甚至没有意义,因为如果你需要定义枚举就比编写接口容易得多.此外,在类或接口中,可能会意外地将相同的值用于多个常量.

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

奖金回合:IDE支持

  • 使用枚举,您可以使用IDE的自动完成功能和自动重构
  • 您可以在Eclipse中使用枚举值中的"查找引用"之类的内容,而您必须执行纯文本搜索以查找字符串文字,这通常也会返回大量误报(如果您使用静态最终常量,则会发生事件,有人可以在某处使用字符串文字)

使用枚举的主要原因是如果您在编译时不知道所有可能的值(即,您需要在程序运行时添加更多值).在这种情况下,您可能希望将它们定义为类层次结构.另外,不要将一堆不相关的常量抛入枚举中并将其称为一天.应该有某种连接值的共同线程.如果更合适,您可以随时制作多个枚举.


Sea*_*oyd 17

枚举是可行的方法,但您可以大大改善您的代码,如下所示:

public static String grow(String type) {
    return Fruits.valueOf(type.toUpperCase()).gimmeFruit();
};
Run Code Online (Sandbox Code Playgroud)

哦,你需要一个默认情况,这会让它变得更加困难.当然你可以这样做:

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

但那很难看.我猜我会这样:

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();
};
Run Code Online (Sandbox Code Playgroud)

此外,如果你的所有枚举方法都返回一个值,你应该重构你的设计,以便在构造函数中初始化值并在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; }
}
Run Code Online (Sandbox Code Playgroud)


JB *_*zet 6

您只有一半的更改更清洁.grow方法应该像这样改变:

static String grow(Fruits type) {
    return type.gimmeFruit();
}
Run Code Online (Sandbox Code Playgroud)

Fruits应该被重新命名为Fruit:苹果是水果,而不是水果.

如果你真的需要保留你的字符串类型,那么定义一个方法(例如在枚举类本身中)返回与每种类型相关的Fruit.但是大多数代码应该使用Fruit而不是String.