Niektóre problemy z singlami enum:
Zaangażowanie w strategię wdrażania
Zazwyczaj „singleton” odnosi się do strategii implementacji, a nie specyfikacji API. Bardzo rzadko Foo1.getInstance()
publicznie deklaruje, że zawsze zwróci tę samą instancję. W razie potrzeby implementacja Foo1.getInstance()
może ewoluować, na przykład zwracając jedną instancję na wątek.
Z Foo2.INSTANCE
Publicznie oświadczam, że ten przypadek jest instancji i nie ma szans, by to zmienić. Strategia wdrażania posiadania pojedynczej instancji jest ujawniona i zobowiązana.
Ten problem nie jest paraliżujący. Na przykład Foo2.INSTANCE.doo()
może polegać na lokalnym obiekcie pomocniczym wątku, aby skutecznie mieć instancję dla wątku.
Rozszerzanie klasy Enum
Foo2
rozszerza super klasę Enum<Foo2>
. Zwykle chcemy unikać superklas; zwłaszcza w tym przypadku narzucona Foo2
superklasa nie ma nic wspólnego z tym, co Foo2
powinno być. Jest to zanieczyszczenie dla hierarchii typów naszej aplikacji. Jeśli naprawdę chcemy superklasy, zwykle jest to klasa aplikacji, ale nie możemy, Foo2
superklasa jest naprawiona.
Foo2
dziedziczy niektóre zabawne metody instancji name(), cardinal(), compareTo(Foo2)
, które są po prostu mylące dla Foo2
użytkowników. Foo2
nie może mieć własnej name()
metody, nawet jeśli ta metoda jest pożądana w Foo2
interfejsie.
Foo2
zawiera także kilka zabawnych metod statycznych
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
co wydaje się bezsensowne dla użytkowników. Singleton zazwyczaj nie powinien mieć metod statycznych pulbic (inaczej niż getInstance()
)
Serializacja
Singletony są bardzo częste. Te singletony zasadniczo nie powinny być serializowane. Nie mogę wymyślić żadnego realistycznego przykładu, w którym sensowne byłoby transportowanie stanowego singletonu z jednej maszyny wirtualnej na inną maszynę wirtualną; singleton oznacza „unikalny w obrębie maszyny wirtualnej”, a nie „unikalny we wszechświecie”.
Jeśli serializacja naprawdę ma sens dla stanowego singletonu, singleton powinien jawnie i precyzyjnie określić, co to znaczy deserializować singleton na innej maszynie wirtualnej, gdzie singleton tego samego typu może już istnieć.
Foo2
automatycznie stosuje uproszczoną strategię serializacji / deserializacji. To tylko wypadek, który czeka. Jeśli mamy drzewo danych koncepcyjnie odnoszące się do zmiennej stanu Foo2
w VM1 w t1, poprzez serializację / deserializację wartość staje się inną wartością - wartością tej samej zmiennej Foo2
w VM2 w t2, tworząc trudny do wykrycia błąd. Ten błąd nie przydarzy się niemożliwym do znalezienia w Foo1
ciszy.
Ograniczenia kodowania
Są rzeczy, które można zrobić w normalnych klasach, ale zabronione w enum
klasach. Na przykład dostęp do pola statycznego w konstruktorze. Programista musi być bardziej ostrożny, ponieważ pracuje w specjalnej klasie.
Wniosek
Piggybacking na enum oszczędzamy 2 linie kodu; ale cena jest zbyt wysoka, musimy dźwigać wszystkie bagaże i ograniczenia wyliczeń, mimowolnie dziedziczymy „cechy” wyliczenia, które mają niezamierzone konsekwencje. Jedyną rzekomą zaletą - automatyczna serializacja - okazuje się być wadą.