列挙型シングルトンに関するいくつかの問題:
実装戦略へのコミット
通常、「シングルトン」とは、API仕様ではなく実装戦略を指します。Foo1.getInstance()
常に同じインスタンスを返すことを公に宣言することは非常にまれです。必要に応じて、Foo1.getInstance()
たとえばの実装を進化させて、スレッドごとに1つのインスタンスを返すことができます。
ではFoo2.INSTANCE
、私たち公にこのインスタンスがあることを宣言し、インスタンス、およびそれを変更する可能性はありません。単一のインスタンスを持つという実装戦略が公開され、コミットされています。
この問題は障害ではありません。たとえばFoo2.INSTANCE.doo()
、スレッドローカルヘルパーオブジェクトに依存して、スレッドごとのインスタンスを効果的に持つことができます。
Enumクラスの拡張
Foo2
スーパークラスを拡張しEnum<Foo2>
ます。通常、スーパークラスは避けたいです。特にこの場合、強制されるスーパークラスは、想定されるFoo2
ものFoo2
とは関係ありません。これは、アプリケーションの型階層に対する汚染です。スーパークラスが本当に必要な場合、通常はアプリケーションクラスですが、できませんFoo2
。スーパークラスは修正されています。
Foo2
継承のようないくつかの面白いインスタンスメソッドname(), cardinal(), compareTo(Foo2)
だけに混乱している、Foo2
のユーザー。そのメソッドがのインターフェースで望ましい場合でもFoo2
、独自のname()
メソッドを持つことはできませんFoo2
。
Foo2
また、いくつかの面白い静的メソッドが含まれています
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
ユーザーには無意味であるように見えます。シングルトンは通常、とにかくpulbic staticメソッドを持つべきではありません(以外getInstance()
)
シリアライズ可能性
シングルトンがステートフルになることは非常に一般的です。通常、これらのシングルトンはシリアル化可能ではありません。あるVMから別のVMにステートフルシングルトンを転送することが理にかなっている現実的な例を考えることはできません。シングルトンとは、「ユニバースの一意」ではなく、「VM内の一意」を意味します。
シリアル化がステートフルシングルトンに対して本当に意味がある場合、シングルトンは、同じタイプのシングルトンが既に存在する可能性がある別のVMでシングルトンを逆シリアル化することの意味を明示的かつ正確に指定する必要があります。
Foo2
単純化されたシリアライゼーション/デシリアライゼーション戦略に自動的にコミットします。それは起こるのを待っているただの事故です。Foo2
t1でVM1の状態変数を概念的に参照するデータのツリーがある場合、シリアル化/逆シリアル化により、値は異なる値になりますFoo2
-t2でVM2の同じ変数の値は、検出が困難なバグを作成します。このバグは、シリアル化不可能なFoo1
サイレントモードでは発生しません。
コーディングの制限
通常のクラスでできることはありますが、クラスでは禁止されていenum
ます。たとえば、コンストラクターで静的フィールドにアクセスします。プログラマーは特別なクラスで働いているため、より注意する必要があります。
結論
enumに便乗することで、2行のコードを保存します。しかし、価格が高すぎるため、enumのすべての荷物と制限を持たなければなりません。意図しない結果をもたらすenumの「機能」を不注意に継承します。主張されている唯一の利点-自動シリアライズ可能性-は、欠点であることが判明しました。