Недавно мы с тобой разбирались, что такое Singleton, как его реализовать на Java и для чего он нужен. Но что если я тебе расскажу, что у Java уже есть свой синглтон из коробки? Интересно? Тогда давай разбираться.
Вероятно, ты уже знаешь о классе enum. У него есть особенность, о которой тебе стоит знать. Дело в том, что enum является реализацией синглтона. Такой вариант почти аналогичен подходу с public полем.
Singleton as enum:
public enum Device {
PRINTER
}
Public variable singleton:
public class Printer {
public static final Printer PRINTER = new Printer();
private Printer() {
}
//…
}
В случае с публичным полем вариант с enum более компактен — не нужно писать свою реализацию. И что самое важное — у енамов нет проблем с сериализацией.
Сериализация здесь работает не так, как для для обычных объектов: сериализируется только значение имени енама. При десериализации метод используется с десериализованным именем, чтобы получить экземпляр. Также enum позволяет защитить себя от рефлексивных атак.
Больше о Reflection ты узнаешь из лекций второго модуля, в теме Reflection API. |
Java представляет запрет на инстанциирование енамов, и это закодировано в реализации метода newInstance класса Constructor, который часто вызывают при создании объектов через рефлексию.
Часть кода из Constructor.newInstance для создания enum:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
Из минусов создания Singleton через enum стоит назвать:
Отсутствие ленивой инициализации, так как объект создается сразу, и нельзя сделать отложенную инициализацию.
Невозможно расширять другие классы. То есть использовать enum как Singleton в случаях, когда нужно наследоваться от другого класса, не получится. В таких случаях нужно обращаться к уже знакомым нам вариантам реализации через статический метод или публичную переменную.
Используя enum как синглтон, ты можешь испольовать только одно поле в enum классе.
public enum Device extends Electricity {
PRINTER
}
Такой код выдаст нам ошибку компиляции:
Но если нам нужно реализовать интерфейс, нет проблем: enum-ы могут имплементировать интерфейсы:
public enum Device implements Electricity {
PRINTER
}
Если тебе не нужно использовать наследование, лучше использовать реализацию Singleton через enum. Так советуем делать не только мы, но и сам Джошуа Блох.
Использование такой реализации дает тебе удобство, компактность, сериализацию из коробки, защиту от рефлексивных атак и уникальность, а это то, что нужно для хорошего Синглтона!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ