Java シングルトンデザインパターン singleton design pattern
singleton design pattern 実装する機会は今までに何度もあったものの、改めて順序だてて考えてみます。
”そのクラスのインスタンスは常に1つしか存在しないことを保証する”こと。
実装にあたって、気をつけたい点
1. どのようにして、インスタンス化を行うのか
2. どのようにして、そのインスタンスが一つだけであることを保証するのか
3. どのようにして、そのシングルのインスタンスを利用できるのか
実装
1. コンフィグファイルを読むためのクラスをシングルトンにしてみます
public class Config { private static Config config = new Config(); private Config(){} public static Config getInstance() { return config; } public String getString(String key) { return "example"; } }
ポイント
1. コンストラクタが private なので、外部からこのインスタンスを生成することはできない
2. config のインスタンスが static で生成されているため、メモリ上に1度しか割り当てされない
> この Config クラスがロードしたときだけ、インスタンスが生成される
> スレッドセーフである
欠点
コンストラクタにパラメータを与えることができないので、柔軟性に欠ける
2. 上記の欠点を補うため、getInstance() 内でコンストラクタを生成するようにしてみます
public class Config { private static Config config; private String pamameter; private Config(String parameter){ this.pamameter = parameter; } public static Config getInstance(String parameter) { if (config == null) { config = new Config(parameter); } return config; } public String getString(String key) { return "example" + pamameter; } }
ポイント
1. getInstance がパラメータを受け取り、それをコンストラクタに渡せるようになった
2. config が null の時だけ、インスタンスを生成しようとしている
欠点
スレッドセーフではない
3. 上記の欠点を補うため、getInstance() を synchronize にしてみます
public class Config { private static Config config; private String pamameter; private Config(String parameter){ this.pamameter = parameter; } public synchronized static Config getInstance(String parameter) { if (config == null) { config = new Config(parameter); } return config; } public String getString(String key) { return "example" + pamameter; } }
ポイント
getInstance() を synchronized にしたので、マルチスレッド下でも重複してインスタンスが生成されない
欠点
synchronized が必要なのはインスタンスが生成されるまでだが、getInstance() が呼ばれる度に判定されてしまう
> 不要なオーバーヘッド
かなり頻繁に getInstance() が呼ばれるケースでは、パフォーマンス面で問題になるかもしれませんね。
上記の欠点については、別の機会に考えます。