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.INSTANCE
uns 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
Foo2
erweitert eine super klasse Enum<Foo2>
. Wir wollen normalerweise Superklassen vermeiden; gerade in diesem Fall hat die aufgezwungene Foo2
Superklasse nichts mit dem zu tun, was sein Foo2
soll. Das ist eine Verschmutzung der Typenhierarchie unserer Anwendung. Wenn wir wirklich eine Superklasse wollen, ist es normalerweise eine Anwendungsklasse, aber wir können nicht, Foo2
die Superklasse ist behoben.
Foo2
erbt einige lustige Instanzmethoden wie name(), cardinal(), compareTo(Foo2)
, die die Foo2
Benutzer nur verwirren . Foo2
Ich kann keine eigene name()
Methode haben, auch wenn diese Methode in Foo2
der 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.
Foo2
legt automatisch eine vereinfachte Serialisierungs- / Deserialisierungsstrategie fest. Das ist nur ein Unfall, der darauf wartet, passiert zu werden. Wenn wir einen Foo2
Datenbaum 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 Foo2
in 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 enum
Klassen 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.