Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Практическое применение Enum


Меня всегда волновал вопрос класса Enum: какие у них есть преимущества перед обычными static final примитивами?

И, если можно, поделитесь вашим опытом, в котором использование Enum было бы действительно оправданным.
    


Ответы

Ответ 1



enum имеет ряд преимуществ при использовании в сравнении с static final int. И использовать его стоит в том случае если вам нужны эти преимущества. Главным отличием является то что используя enum вы можете проверить тип данных. Например: public class SomeClass { public static int RED = 1; public static int BLUE = 2; public static int YELLOW = 3; public static int GREEN = 3; // Совпадающие значения private int color; public void setColor(int color) { this.color = color; } } При этом вы можете передать в класс любое значение int. new SomeClass().setColor(999); Следовательно, основные проблемы использования static final int это: Необходимость проверки вводимых данных. Нет никакой защиты от создания static final int переменной с дублирующимся значением. Еще одним преимуществом enum является возможность перегружать методы. public enum UnitConverter{ METERS{ @Override public double toMiles(final double meters){ return meters * 0.00062137D; } @Override public double toMeters(final double meters){ return meters; } }, MILES{ @Override public double toMiles(final double miles){ return miles; } @Override public double toMeters(final double miles){ return miles / 0.00062137D; } }; public abstract double toMiles(double unit); public abstract double toMeters(double unit); } Недостатки использования enum К ним не применимы операторы >, <, >=, <=. Следовательно enum не стоит применять в списке последовательных данных. enum также требует больше памяти для хранения чем обычная константа. IntDef и StringDef в Android Google не рекомендует использовать enum в Android приложениях из-за того что эт требует больше памяти. Вместо этого для Android можно использовать IntDef и StringDe которые позволяют ограничивать пространство значений для обычных констант. Следовательно, вы получаете главное преимущество enum не теряя в использовании памяти. Это практика повсеместно используется в стандартных классах Android: /** @hide */ @IntDef({VISIBLE, INVISIBLE, GONE}) @Retention(RetentionPolicy.SOURCE) public @interface Visibility {} /** * This view is visible. * Use with {@link #setVisibility} and {@code * android:visibility}. */ public static final int VISIBLE = 0x00000000; /** * This view is invisible, but it still takes up space for layout purposes. * Use with {@link #setVisibility} and {@code * android:visibility}. */ public static final int INVISIBLE = 0x00000004; /** * This view is invisible, and it doesn't take any space for layout * purposes. Use with {@link #setVisibility} and {@code * android:visibility}. */ public static final int GONE = 0x00000008; В принимающем методе используется специальная аннотация: public void setVisibility(@Visibility int visibility) { setFlags(visibility, VISIBILITY_MASK); if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false); } В таком случае вы не сможете использовать другую константу для этого метода: view.setVisibility(456);//Error: Must be one of: View.VISIBLE, View.INVISIBLE, View.GONE

Ответ 2



Перечисления (Enum) удобно использовать для представления множества взаимоисключающих состояний. Пример Перечисления кодов сообщения: enum MessageCode { // Установка однозначного соответствия // между элементом перечисления и целочисленным значением. UNKNOWN(0), TOAST(1), MESSAGE(2); private final int id; MessageCode(int code) { id = code; } // Метод получения целочисленного значения, // соответствующего выбранному элементу Перечисления (Enum) public int getId() { return id; } // Метод получения элемента Перечисления (Enum), // соответствующего переданному целочисленному значению public static MessageCode fromId(int code) { MessageCode[] list = MessageCode.values(); if (code >= 0 && code < list.length) return list[code]; else return MessageCode.UNKNOWN; } } Пример анализа сообщений: private Messenger chatUIThreadMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msg) { String str; switch (MessageCode.fromId(msg.what)) { // Доступ к выводу Toast'ов для Thread'ов прослушивающих Socket'ы case TOAST: str = (String) msg.obj; Toast.makeText(getBaseContext(), str, Toast.LENGTH_LONG).show(); break; // Вывод сообщений в лог чата case MESSAGE: str = (String) msg.obj; messages.add(str); messagesAdapter.notifyDataSetChanged(); final ListView listView = (ListView) findViewById(R.id.listViewChat); listView.smoothScrollToPosition(messagesAdapter.getCount() - 1); break; // Исключительная ситуация case UNKNOWN: Toast.makeText(getBaseContext(), "Messenger: неопределённый тип сообщения!", Toast.LENGTH_LONG).show(); break; default: super.handleMessage(msg); } } });

Ответ 3



Использование enum вместо констант полезно, например, когда вы хотите ограничит возможное множество значений аргумента к-л метода. Если использовать к-л константу (in или String, например), и метод, который должен её принимать будет иметь соответствующий тип аргумента, то ничто вам не помешает передать туда что-то помимо констант. Если же вы используете enum то передать что-то кроме enum у вас не получится.

Ответ 4



Enum можно использовать как реализацию паттерна Singleton. Преимущества: Сериализация из коробки Потокобезопасность из коробки Возможность использования EnumSet, EnumMap и т.д Поддержка switch Недостатки Не ленивая инициализация По мнению Joshua Bloch’а это лучший способ реализации шаблона public enum Singleton { INSTANCE; }

Комментариев нет:

Отправить комментарий