Нещодавно ми з тобою розбиралися, що таке Singleton, як його реалізувати в Java і для чого він потрібен. Але що якщо я тобі розповім, що Java вже має свій синглтон із коробки? Цікаво? Тоді давай розбиратися.
Мабуть, ти вже знаєш про клас enum. Він має особливість, про яку тобі варто знати. Справа в тому, що enum є реалізацією синглтона. Такий варіант майже аналогічний підходу із public полем.
Singelton 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. Так радимо робити не лише ми, а й сам Джошуа Блох.
Використання такої реалізації дає тобі зручність, компактність, серіалізацію із коробки, захист від рефлексивних атак та унікальність, а це те, що потрібно для гарного Синглтона!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ