Некоторые проблемы с синглетонами 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 строки кода; но цена слишком высока, мы должны нести все мешки и ограничения перечислений, мы непреднамеренно наследуем «особенности» перечислений, которые имеют непредвиденные последствия. Единственное заявленное преимущество - автоматическая сериализуемость - оказывается недостатком.