Некоторые проблемы с синглетонами enum:
Приверженность стратегии реализации
Как правило, «синглтон» относится к стратегии реализации, а не к спецификации API. Очень редко Foo1.getInstance()публично заявляют, что он всегда будет возвращать один и тот же экземпляр. При необходимости реализация Foo1.getInstance()может развиваться, например, для возврата одного экземпляра на поток.
С Foo2.INSTANCEмы публично заявляем , что данный экземпляр экземпляр, и нет никаких шансов , чтобы изменить это. Стратегия реализации, состоящая в том, чтобы иметь единственный экземпляр, является открытой и преданной.
Эта проблема не наносит вред. Например, Foo2.INSTANCE.doo()может полагаться на локальный вспомогательный объект потока, чтобы эффективно иметь экземпляр для каждого потока.
Расширение класса Enum
Foo2расширяет супер класс Enum<Foo2>. Мы обычно хотим избегать супер-классов; особенно в этом случае, вынужденный суперкласс Foo2не имеет ничего общего с тем, что Foo2должно быть. Это загрязнение иерархии типов нашего приложения. Если мы действительно хотим суперкласс, обычно это класс приложения, но мы не можем, Foo2суперкласс исправлен.
Foo2наследует некоторые забавные методы экземпляра name(), cardinal(), compareTo(Foo2), которые просто сбивают с толку Foo2пользователей России. Foo2не может иметь свой собственный name()метод, даже если этот метод желателен в Foo2интерфейсе.
Foo2 также содержит несколько забавных статических методов
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
который кажется бессмысленным для пользователей. У синглтона обычно не должно быть пульсирующих статических методов в любом случае (кроме getInstance())
Сериализуемость
Синглтонам очень свойственно быть с состоянием. Эти синглтоны обычно не должны быть сериализуемыми. Я не могу вспомнить ни одного реалистичного примера, когда имеет смысл переносить синглтон с состоянием с одной виртуальной машины на другую; «Синглтон» означает «уникальный внутри ВМ», а не «уникальный во вселенной».
Если сериализация действительно имеет смысл для синглтона с состоянием, то синглтон должен явно и точно указать, что значит десериализовать синглтон в другой виртуальной машине, где синглтон того же типа может уже существовать.
Foo2автоматически фиксирует упрощенную стратегию сериализации / десериализации. Это просто несчастный случай, ожидающий случиться. Если у нас есть дерево данных, концептуально ссылающееся на переменную состояния Foo2в VM1 в момент времени t1, посредством сериализации / десериализации значение становится другим значением - значением той же переменной Foo2в VM2 в момент времени t2, что создает трудно обнаруживаемую ошибку. Эта ошибка не произойдет с не сериализуемым Foo1молча.
Ограничения кодирования
Есть вещи, которые можно делать в обычных классах, но запрещать в enumклассах. Например, доступ к статическому полю в конструкторе. Программист должен быть более осторожным, поскольку он работает в специальном классе.
Вывод
Используя перечисление enum, мы сохраняем 2 строки кода; но цена слишком высока, мы должны нести все мешки и ограничения перечислений, мы непреднамеренно наследуем «особенности» перечислений, которые имеют непредвиденные последствия. Единственное заявленное преимущество - автоматическая сериализуемость - оказывается недостатком.