こんにちは。まさきです。
今回はデザインパターンの1つであるシングルトンパターンについてJavaでの実装方法と使い方を解説していきます。
今回は以下の参考書を元にまとめております。
JavaプログラマGold SE8
Java言語で学ぶデザインパターン入門第3版
シングルトン(Singleton)とは
まずデザインパターンとは、システムの開発のために多くの経験や情報をもとに作られた問題解決方法です。
その中でシングルトンパターンというものがあります。
シングルトンパターンとは、『あるクラスのインスタンスがシステム内で1個しか存在しない』状態を保証するパターンのことです。
Javaではクラスから「new クラス名」とすることでインスタンスが生成され、それを使用して処理を行います。
この場合はインスタンスは生成した数だけ作成されますが、これを1つだけ作成して使いまわすことがシングルトンパターンです。
じゃあ「ソース上でnewしなければいい」と思うかもしれませんが、それでは仕様を知らない新規の実装者が書いてしまうかもしれませんし、確実にインスタンスが1つしかないことを保証できません。
そこでJavaのコード上でインスタンスを1つしか作れない作りにしてしまえば、インスタンスは1つしか存在しないことを保証できるというわけです。
またSingleton(シングルトン)は『要素を1つしか持たない集合』の意味なのでそこからシングルトンパターンと呼ばれています。
シングルトンパターンを実現するポイント
言葉での説明はご説明しましたが、ではどのように実装すればよいかをここからご説明します。
Javaでシングルトンパターンを実現するポイントは3つです。
- インスタンス変数は一度だけインスタンスを生成し更新不可とする
- コンストラクタは外部から呼び出させない
- インスタンス変数を返却するゲッターを用意する
ではもう少し詳しく説明します。
インスタンス変数は一度だけインスタンスを生成し更新不可とする
インスタンス変数は一度だけ生成し、更新や初期化はできないようにします。
そのためprivateとfinalを指定します。
finalを指定することで上書きができなくなり、privateでクラス外からの参照を防ぎます。
finalを指定しているため定数となるため初期化は必要になります。
コンストラクタは外部から呼び出させない
コンストラクタを明示的に記載することで外部デフォルトコンストラクタの追加を防ぎ、privateを指定することで外部からインスタンス化を行えなくなります。
コンストラクタでのインスタンス変数が初期化されることを防ぎます。
インスタンス変数を返却するゲッターを用意する
上記の2つでは外部からアクセスができず使うことができないため、publicで指定したゲッターを用意してインスタンス変数を返却することで1つのインスタンス変数を使いまわすことができます。
コード解説
では上記のポイントをJavaのコードにした場合の書き方をMySingletonクラスに書いていきます。
public class MySingleton {
//①1つだけのインスタンス
private static final MySingleton INSTANCE = new MySingleton();
//②コンストラクタ
private MySingleton() {}
//③インスタンス取得メソッド
public static MySingleton getInstance() {
return INSTANCE;
}
//その他処理
public void print(){
System.out.print("Singleton");
}
}
インスタンスは外部から直接アクセスされないようにするためprivate、
後から更新されないようにfinalを指定すると初期化が必要になるのでクラスのロード時のみ初期化されるようにインスタンス化したオブジェクトを代入、
1つのオブジェクトを保持し続けるためにstaticを指定します。
一応定数なので大文字で宣言。
コンストラクタはデフォルトコンストラクタの追加を防ぐように引数なしで記載、
外部からのインスタンス化を防ぐためにprivateを指定します。
処理があったら書いてもいいですが今回は特に記載しません。
ゲッターは外部から呼び出せるようにするためpublic、
staticなインスタンス変数を参照するためstaticを指定、
自分自身のインスタンスを返却するために戻り値の方は自分自身(MySingleton)
あとはクラスに必要な処理を記載すればOKです!
呼び出し方の例はこのようになります。
public class SingletonMain {
//Mainメソッド
public static void main(String[] args) {
//[OK] getInstanceを使用して呼び出す
MySingleton mySingleton1 = MySingleton.getInstance();
//[NG] newを使って新しくインスタンスを作る
//MySingleton mySingleton2 = new MySingleton();
//メソッドの使用
mySingleton1.print();
}
}
外部のクラスから呼び出すにはゲッターで作成したgetInstanceを使用します。
7行目のようにnewを使って新しくインスタンスを作ろうとするとコンパイルエラーになります。
このようにgetInstanceで取得したインスタンスはコード上も1つしか存在できないので必ず同じインスタンスを使うことになります。
シングルトンの使いどころ
シングルトンにするとインスタンス1つを使いまわすことになります。
そのため共通的に使用されるような場合にシングルトンで作られることがあります。
・システム情報を保持するクラス
・設定ファイルから読み込んだ値を保持するクラス
・データベース接続ドライバ
・ログ出力やキャッシュ管理などの共通処理
他にはインスタンスの生成処理が重いクラスでも使用を検討できます。
Javaの場合、java.lang.Runtimeクラスで使用されています。
java.lang.Runtimeはメモリ情報の取得やexeファイルの実行といったことができるクラスで、プログラムの実行環境の情報を持っています。
java.lang.Runtimeもインスタンスを取得する場合はgetRuntimeメソッドを使ってインスタンスを取得します。
このようにJava標準のソースでも使っているコードはあるので気になった方はeclipseなどでJavaのソースを直接見てみてください!
ただしシングルトンパターンの注意点として、シングルトンで実装するとテストが難しくなるので注意しましょう。
シングルトンの解説は以上になります。
最後まで読んで頂きありがとうございました!
今回参考にした参考書はこちらになりますので、気になったら読んでみてください。
Java Goldは資格の参考書ですがJavaの中上級者向けの基礎が詰め込まれています。
私が持っているのはバージョンが8で少し前なので新しいバージョンの方もチェックしてみてください。
Java言語で学ぶデザインパターン入門はシングルトンのような様々なデザインパターンが書いてあるので、Javaの読み書きを一通りできて設計レベルでさらにレベルアップしたい方向けです。