Я искал несколько дней, чтобы найти ответ на эту проблему, основанную на производительности.
Покопавшись в Интернете, я узнал, что есть несколько способов использования 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? Скорее, чтобы было понятно, в чем разница в производительности?