Einige Probleme mit Enum Singletons:
Bekenntnis zu einer Umsetzungsstrategie
In der Regel bezieht sich "Singleton" auf eine Implementierungsstrategie und nicht auf eine API-Spezifikation. Es ist sehr selten Foo1.getInstance(), dass öffentlich deklariert wird, dass immer dieselbe Instanz zurückgegeben wird. Bei Bedarf kann die Implementierung vonFoo1.getInstance() so weiterentwickelt werden, dass eine Instanz pro Thread zurückgegeben wird.
Mit Foo2.INSTANCEuns erklären öffentlich , dass diese Instanz ist die Instanz ist, und es gibt keine Chance, das zu ändern. Die Implementierungsstrategie, eine einzelne Instanz zu haben, wird offengelegt und begangen.
Dieses Problem lähmt nicht. Beispielsweise Foo2.INSTANCE.doo()kann auf ein Thread-lokales Hilfsobjekt zurückgegriffen werden, um effektiv zu arbeiten eine Instanz pro Thread zu haben.
Erweiterung der Enum-Klasse
Foo2erweitert eine super klasse Enum<Foo2>. Wir wollen normalerweise Superklassen vermeiden; gerade in diesem Fall hat die aufgezwungene Foo2Superklasse nichts mit dem zu tun, was sein Foo2soll. Das ist eine Verschmutzung der Typenhierarchie unserer Anwendung. Wenn wir wirklich eine Superklasse wollen, ist es normalerweise eine Anwendungsklasse, aber wir können nicht, Foo2die Superklasse ist behoben.
Foo2erbt einige lustige Instanzmethoden wie name(), cardinal(), compareTo(Foo2), die die Foo2Benutzer nur verwirren . Foo2Ich kann keine eigene name()Methode haben, auch wenn diese Methode in Foo2der Benutzeroberfläche wünschenswert ist .
Foo2 enthält auch einige lustige statische Methoden
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
was für Benutzer unsinnig erscheint. Ein Singleton sollte normalerweise sowieso keine pulbischen statischen Methoden haben (außer der getInstance())
Serialisierbarkeit
Singletons sind sehr häufig staatlich. Diese Singletons sollten im Allgemeinen nicht serialisierbar sein. Ich kann mir kein realistisches Beispiel vorstellen, bei dem es sinnvoll ist, einen statusbehafteten Singleton von einer VM zu einer anderen zu transportieren. Ein Singleton bedeutet "einzigartig innerhalb einer VM", nicht "einzigartig im Universum".
Wenn die Serialisierung für ein statusbehaftetes Singleton wirklich Sinn macht, sollte das Singleton explizit und genau angeben, was es bedeutet, ein Singleton in einer anderen VM zu deserialisieren, in der möglicherweise bereits ein Singleton desselben Typs vorhanden ist.
Foo2legt automatisch eine vereinfachte Serialisierungs- / Deserialisierungsstrategie fest. Das ist nur ein Unfall, der darauf wartet, passiert zu werden. Wenn wir einen Foo2Datenbaum haben, der konzeptionell auf eine Zustandsvariable von in VM1 zu t1 verweist, wird der Wert durch Serialisierung / Deserialisierung zu einem anderen Wert - der Wert derselben Variablen von Foo2in VM2 zu t2, wodurch ein schwer zu erkennender Fehler entsteht. Dieser Fehler tritt nicht bei den unserializable aufFoo1 .
Einschränkungen der Codierung
Es gibt Dinge, die in normalen Klassen gemacht werden können, aber in enumKlassen verboten sind. Zum Beispiel auf ein statisches Feld im Konstruktor zugreifen. Der Programmierer muss vorsichtiger sein, da er in einer speziellen Klasse arbeitet.
Fazit
Durch Huckepack auf Enum sparen wir 2 Codezeilen; aber der Preis ist zu hoch, wir müssen alle Gepäckstücke und Beschränkungen von Aufzählungen tragen, wir erben versehentlich "Merkmale" von Aufzählungen, die unbeabsichtigte Konsequenzen haben. Der einzige vermeintliche Vorteil - die automatische Serialisierbarkeit - erweist sich als Nachteil.