Java Enums - операторы переключения против шаблона посетителя в перечислениях - преимущества производительности?

Я искал несколько дней, чтобы найти ответ на эту проблему, основанную на производительности.
Покопавшись в Интернете, я узнал, что есть несколько способов использования Enums в java, хорошо задокументированных в здесь. Что ж, определенно в качестве начального хотелось бы использовать Enums в операторе switch-case, который обеспечивает ясность и лучшее понимание кода. Но, с другой стороны, у нас также есть реализация Enums в стиле шаблона посетителя, которая обеспечивает безопасность типов и расширяемость. Обсуждается здесь.

Сказав это и вернувшись к исходной идее, лежащей в основе этого вопроса, до сих пор я узнал, что если конструкция switch-case правильно спроектирована с использованием Enums, что гарантирует, что значения case не являются разреженными, и что объявление Enum находится в том же модуль компиляции в качестве оператора switch-case, компилятор java выполняет некоторую оптимизацию созданного байт-кода, реализуя такую ​​конструкцию, как Таблица переходов (обсуждается в здесь и в другом месте на веб-сайте Sun, ссылку на который я потерял). Теперь это определенно дает прирост производительности по сравнению с множественной / вложенной конструкцией if-else.

У меня вопрос: как Java реализует реализацию Enums на основе шаблонов посетителей в результирующем байт-коде и каково повышение производительности по сравнению с реализацией на основе switch-case, если таковая имеется?

И какой тип реализации я должен предпочесть, учитывая, что мои Enums могут расти в будущем, и я также заинтересован в производительности. В настоящее время в моем Enum есть 19 с лишним констант.


ИЗМЕНИТЬ
У меня есть класс, в котором хранится некоторая информация о переменных игры. Одна из переменных является типом Enum.

public class GameObject {
    private Shape mShape;

    public Shape getShape() {
        return mShape;
    }
    .
    .
    .

    public static enum Shape {
        SHAPE1, SHAPE2, SHAPE3, SHAPE4, ..., SHAPE20
    };

    public void drawShape() {
        switch (this.mShape) {
        case SHAPE1:
            drawShape1();
            break;
        case SHAPE2:
            drawShape2();
            break;
        case SHAPE3:
            drawShape3();
            break;
        case SHAPE4:
            drawShape4();
            break;
        .
        .
        .
        .
        .
        case SHAPE20:
            drawShape20();
            break;
        default:
            drawUnknown();
            break;
        }
    }

}

Позже я понял, что нужно отделить информацию от логики, и поэтому создал другой класс и переместил Enum Shape из GameObject к этому новому классу GraphicModel, и вместо того, чтобы иметь там switch-case, я реализовал методы, специфичные для констант. И да, после этой модификации я поместил правильные операторы импорта в любой из классов.

public class GraphicModel {
    public void drawGraphicFromObject(GameObject gameObject) {
        gameObject.getShape().draw();
    }

    public static enum Shape {
        // This method is not public, instead is only called by GraphicModel
        abstract void draw();

        SHAPE1 {
            @Override
            void draw() {
                // some transformations
            }
        },
        SHAPE2 {
            @Override
            void draw() {
                // Some different transformation
            }
        },
        SHAPE3 {
            @Override
            void draw() {
                // Yet another transform
            }
        },
        .
        .
        .
        .
        UNKNOWN {
            @Override
            void draw() {
                // 
            }
        };
    }
}

Позже я даже реализовал это на основе шаблона посетителя, как было предложено здесь

Итак, что мне нужно знать, так это то, какой способ реализации более эффективен? Определенно, для преобразования switch-case в таблицы переходов при компиляции java требует как объявления enum, так и switch операторы в той же единице компиляции. Должен ли я использовать реализацию на основе переключателя или реализацию метода, зависящего от константы в моем классе GraphicModel? Скорее, чтобы было понятно, в чем разница в производительности?


person Darkfish    schedule 29.01.2010    source источник
comment
У вас есть пример наиболее четко написанного кода, а также спецификация и результаты тестирования, показывающие, как он не соответствует спецификации? Если нет, то вам пока не следует думать об этом. Если это так, опубликуйте четко написанный код, и я уверен, что мы сможем найти гораздо более значительные оптимизации.   -  person Bill K    schedule 29.01.2010
comment
Связанный вопрос SO рассказывает, как Enums можно использовать с шаблоном посетителя, а не с реализацией шаблона посетителя Enums. Думаю, будет лучше, если вы расскажете, какую проблему пытаетесь решить. Как только вы увидите, что перечисления можно использовать как решение вашей проблемы, вы сможете увидеть, нужно ли его оптимизировать.   -  person sateesh    schedule 29.01.2010
comment
Это похоже на тип микро-микро-микрооптимизации, который не дает заметного эффекта в 99,99% случаев.   -  person matt b    schedule 29.01.2010
comment
Прошу прощения, если я не смог должным образом изложить свое понимание в формальных терминах, честно говоря, я никогда не разбирался в таких терминах, хотя я использовал такие методологии. И я считаю, что да, я использовал здесь неправильный термин, как упоминалось в сообщении Дитера, это называется реализация метода, зависящего от константы. И я опубликую образец кода того, что имел в виду сегодня. Когда я писал здесь, было 5 утра. Спасибо всем за указатели. Я согласен с Мэттом, но у меня остается вопрос, что более эффективно, даже если оно дает только микроминимальный прирост?   -  person Darkfish    schedule 30.01.2010
comment
Второй - скорее стратегия, чем шаблон посетителя.   -  person helpermethod    schedule 01.06.2010
comment
В «Эффективном Jave», 2-е изд., Дж. Блох приводит убедительный аргумент в пользу того, что блоки switch-case не должны регулярно использоваться для перебора констант перечисления. Он продолжает развивать идею о том, что использование методов, специфичных для констант, вместо switch-case часто может привести к менее хрупкому и более удобному в сопровождении коду. Применяя это рассуждение к вашему вопросу, я бы сказал, что проблемы с производительностью вряд ли будут важны (вам нужно будет профилировать, чтобы увидеть), но преимущества разработки программного обеспечения шаблона методов, специфичных для констант, способствуют их использованию по сравнению с переключателем. .   -  person scottb    schedule 09.09.2013


Ответы (1)


Перечисления, вообще говоря, сравнимы по производительности с константами int, если они используются в инструкции switch (1).

Может быть, вам лучше рассмотреть что-то вроде реализации конкретных методов для констант? например

public enum Mode {

  ON { Color color() {return Color.GREEN;}},
  OFF { Color color() {return Color.RED;}},
  STANDBY { Color color() {return Color.YELLOW;}},
  DEFAULT { Color color() {return Color.BLACK;}};

  abstract Color color();

}//enum Mode

А затем используйте

getMode().color();

вместо оператора switch ?!

Однако я думаю, что для случая «получить только цвет» методы могут вообще не понадобиться.

В общем, я настоятельно рекомендую вам Эффективная Java для вашей книжной полки. В главе 6 обсуждаются перечисления и аннотации.

person Dieter    schedule 29.01.2010
comment
Спасибо за предложение, но во второй раз я поступил именно так. Я тоже посмотрю книгу. - person Darkfish; 30.01.2010