![translation](https://cdn.durumis.com/common/trans.png)
To jest post przetłumaczony przez AI.
Wybierz język
Tekst podsumowany przez sztuczną inteligencję durumis
- Singleton to klasa, która może utworzyć tylko jedną instancję, używaną do tworzenia obiektów bezstanowych lub unikalnych komponentów systemu.
- Istnieją trzy sposoby tworzenia singletonów: użycie publicznych statycznych członków jako pól finalnych, dostarczanie statycznych metod fabrycznych lub użycie typów wyliczeniowych, z których najbardziej pożądanym jest użycie typów wyliczeniowych.
- Podczas serializacji klasy singleton należy zaimplementować Serializable, zadeklarować wszystkie pola instancji jako transient i nadpisać metodę readResolve().
Singleton
Koncepcja Singletona
Singleton to klasa, która może utworzyć tylko jeden egzemplarz. Typowe przykłady singletonów to obiekty bezstanowe lub unikalne komponenty systemowe. Jednak klasy singletonowe są trudne do przetestowania, jeśli nie są zdefiniowane jako typ z interfejsem i jego implementacją.
Jak stworzyć singleton
Publiczny statyczny członek jako pole finalne
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void speak() {
System.out.println("elvis");
}
Prywatny konstruktor jest wywoływany tylko raz podczas inicjalizacji instancji Elvis, gwarantując, że jest to jedyny egzemplarz w całym systemie. Jednak metoda AccessibleObject.setAccessible() pozwala na wywołanie prywatnego konstruktora, a ta metoda modyfikacji za pomocą refleksji może być zablokowana poprzez wyrzucenie wyjątku podczas tworzenia drugiego obiektu.
- Zalety
- API wyraźnie pokazuje, że klasa jest singletonem.
- Jest zwięzły.
Statyczna metoda fabryczna jako publiczny statyczny człon
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void speak() {
System.out.println("elvis");
}
Oprócz modyfikacji za pomocą refleksji, ta metoda również gwarantuje, że jest to jedyny egzemplarz w całym systemie. Po prostu pole jest prywatne, a zwracanie obiektu odbywa się za pomocą statycznej metody fabrycznej.
- Zalety
- Możliwość zmiany na nie-singleton bez zmiany API.
- Na przykład, statyczna metoda fabryczna może zwracać różne instancje dla każdego wątku.
- Możliwość przekształcenia w generyczną fabrykę singletonów.
- Możliwość użycia odwołania do metody statycznej fabrycznej jako dostawcy.
- Na przykład, zamiast Elvis::getInstance można użyć Supplier<Elvis>.
- Możliwość zmiany na nie-singleton bez zmiany API.
Jeśli nie potrzebujesz korzystać z powyższych zalet, lepiej jest użyć pierwszej metody.
Używanie typu wyliczeniowego
public enum Elvis {
INSTANCE;
public void speak() {
System.out.println("elvis");
}
Najlepszą metodą jest użycie typu wyliczeniowego. Jest bezpieczniejszy przed atakami refleksyjnymi niż dwie poprzednie metody i ma czystszy kod. Ponadto, jak wspomniano poniżej, dwie poprzednie metody mają wadę, że wymagają dodatkowego kodu podczas serializacji.
Należy jednak pamiętać, że tworzony singleton może dziedziczyć z interfejsu, ale nie z klasy.
Punkty do zapamiętania podczas serializacji klasy singleton
Aby zserializować klasę singleton utworzoną przy użyciu pierwszej lub drugiej metody, poza prostym zaimplementowaniem interfejsu Serializable, należy zadeklarować wszystkie pola instancji jako transient i przesłonić metodę readResolve().
private Object readResolve throws ObjectStreamException {
return INSTANCE;