Несколько If-else или enum - какой из них предпочтительнее и почему? - PullRequest
15 голосов
/ 25 мая 2011

Вот оригинальный код:

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

Я вижу, что код enums длиннее и может быть не таким четким, как код if-else, но я считаю, что лучше, может кто-нибудь сказать мне, почему я ошибаюсь (или, возможно, я не)? 1009 *

UPD - изменен исходный код, чтобы он был более специфичным для проблемы. Я перефразирую вопрос: есть ли опасения по поводу использования enum вместо if-else?

Ответы [ 14 ]

2 голосов
/ 25 мая 2011

Я второй Шон Патрик Флойд о том, что перечисления - это путь, но я хотел бы добавить, что вы можете значительно сократить свое событие кода, используя следующую схему:метод "расти" является подозрительным.Разве это не должно быть что-то вроде

public static String grow(Fruits f) {
   return f.gimmeFruit();
}
1 голос
/ 22 июня 2011

Если бы у разных Фруктов было разное поведение роста, я бы не использовал if-else или enum, а вместо этого использовал бы объектно-ориентированный дизайн. Проблема со стилем if-else / enum (я считаю их эквивалентными в вашем примере) заключается в том, что они собирают поведение различных типов объектов в одном месте. Если вы добавляете новый фрукт, вам нужно каждый раз редактировать свой if-else / enum. Это нарушает принцип открытый-закрытый .

Подумайте, было ли у ваших 4 плодов 3 поведения (например, расти, созревать, гнить). У вас будет if-else / enum для каждого поведения, каждое из которых содержит 4 ссылки на фрукты. Теперь рассмотрите возможность добавления 5-го фрукта, вы должны отредактировать 3 разных блока if-else / enum. Поведение арбуза не имеет ничего общего с яблоком, но они в одном куске кода. Теперь рассмотрите возможность добавления нового фруктового поведения (например, аромат) - вы должны создать новый if-else / enum, который имеет те же проблемы.

Я считаю, что правильное решение в большинстве случаев - использовать классы (например, интерфейс / базовый класс Fruit с одним классом реализации на фрукт) и поместить поведение в каждый класс вместо того, чтобы собирать все в одном месте. Поэтому, когда вы добавляете новый фрукт, единственный изменяемый код состоит в том, что пишется новый класс фруктов.

Существует хорошо известный рефакторинг, который вы можете использовать, чтобы взять существующий код и перенести его в то, о чем я говорю. Это называется Заменить условное на полиморфизм .

1 голос
/ 22 июня 2011

Ну, код перечисления, конечно, длиннее. Что я предлагаю:

  • Используйте строки, когда логика проста, мала и будет использоваться 1 раз.
  • Используйте Enums, когда вам приходится многократно использовать константы, возможно добавление или изменение, или когда они смешаны в сложном коде, так что лучше их уточнить с помощью Enum.
1 голос
/ 21 июня 2011

Чтобы ответить на ваш вопрос, я бы сказал, что ни if-else, ни enums не являются предпочтительными для вашей конкретной проблемы.Хороший способ решить эту проблему - использовать инкапсуляцию и абстракцию и позволить наследованию обрабатывать «тип» для вас.

Задача выращивания фрукта сильно варьируется в зависимости от каждого фрукта.Было бы разумно сделать каждый фрукт отдельным классом, обеспечивающим большую гибкость в дальнейшем, когда потребуется больше функциональности.

Вот хороший пример:

// Abstract Base Class (Everything common across all fruits)
public abstract class Fruit {
    public abstract void grow();
}

// Concrete class, for each "type" of fruit
public class Apple extends Fruit {
    @override
    public void grow() {
        // Grow an apple
    }
}

public class Orange extends Fruit {
    @override
    public void grow() {
        // Grow an orange
    }
}

...

Как только классы продуктов были определенымы можем создать класс, который выращивает фрукты без проверки типа "ify".

public class FruitGrower {
    public void growAFruit(Fruit fruit) {
        fruit.grow();
    }
}
...