Деякі проблеми з перерахунком синглів:
Прихильність до стратегії впровадження
Як правило, "одиночний" відноситься до стратегії реалізації, а не до специфікації 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 рядки коду; але ціна занадто висока, нам доводиться нести всі сумки та обмеження переліків, ми ненавмисно успадковуємо "риси" перерахунків, які мають непередбачувані наслідки. Єдина передбачувана перевага - автоматична серіалізація - виявляється недоліком.