本記事ではGoFのデザインパターンのオブジェクトの生成に関するパターンの一つである「Singleton」パターンを解説します。このパターンを一言で説明するならば、「クラスのオブジェクトが1つしか生成されないことを保証する」と言えるでしょう。文章では想像がつきにくいと思いますので、例を踏まえながら解説していきます。
「Singleton」パターンとは?
先述した通り、「Singleton」パターンとは「クラスのオブジェクトが1つしか生成されないことを保証する」パターンです。「Singleton」は直訳すると「単一の」という意味があります。Javaのクラスはオブジェクトの設計図であり、その設計図から複数のオブジェクトを生成することができます。しかし、「Singleton」では絶対に一つのオブジェクトしか作られないようにするパターンです。
では「Singleton」パターンはどんな時に威力を発揮するのでしょうか。それは、アプリケーション内の設定を行うクラスや、ログを収集するクラス等で活躍できます。設定を行うオブジェクトを複数生成できてしまうと、最初に生成した設定と後から生成した設定が違うものになり、バグを生んでしまうことが考えられます。また、ログを出力するクラスのオブジェクトが複数生成できてしまうと、出力先の不一致や、ログの出力順序で競合が起きてしまう可能性があります。このような場合に「Singleton」パターンを利用するといいでしょう。
また、不要なオブジェクトの生成を防げるため、CPUやメモリのリソースを抑えることができます。
しかしながら、あまり多用はしないほうがいいとの記事を多く見かけます。CPUのメモリやリソースを抑えるためにあえて利用する必要はないです。あくまでコードの設計上、複数のオブジェクトが生成されないようにするために利用すべきです。記事の中には「Singleton」の誘惑に負けるなという記事もありました。
下記の記事では、「Singleton」パターンの弊害がわかりやすく載っていました。是非参考にしてみてください。
・シングルトンパターンの誘惑に負けない
「Singleton」の書き方
ではサンプルケースを踏まえて実装方法を解説します。運転免許書の例をあげてみましょう。運転免許書は「Singleton」のパターンだと言えるでしょう。免許のデータ自体は別のところに保存されていますが、個人に交付される運転免許書は絶対に1枚です。2枚交付されることは決してなく、運転免許書の有効期限が切れたとしても、この世に自分の運転免許書は1枚しかありません。
またこの運転免許書は、いろいろなところで身分証明書てして提示することがあります。もちろん2枚あることはないので、毎回同じ運転免許書(オブジェクト)を提示するはずです。運転免許書のクラスを「Singleton」パターンを用いて作成してみます。
public class Card {
private static final Card card = new Card();
// コンストラクタ
private Card() {
// Cardクラスのインスタンスの初期化処理
}
public static Card getInstance() {
return card;
}
}
「Singleton」のクラスにするのは非常に簡単で、クラスのコンストラクタをprivateなコンストラクタにします。デフォルトではpublicになっていいます。privateなコンストラクタにすることで、クラス外からコンストラクタを利用してインスタンスを生成できなくなります。
このクラスのインスタンスは静的フィールドとしてあらかじめコンストラクタを利用して生成します。ここではクラス内部なのでコンストラクタが利用できます。生成したインスタンを変更されたくない場合、finalをつけて変更不可能なオブジェクトとします。
この静的フィールドもprivateなフィールドのため外部から利用できません。そこでgetInstance()メソッドを作成します。このメソッドはprivateなメソッドなため外部から利用が可能です。
この「Singleton」のクラスを利用すると下記のようになります。
Card card1 = Card.getInstance();
Card card2 = Card.getInstance();
if (card1 == card2) {
System.out.println("2つは全く同じオブジェクトを参照しています。");
}
オブジェクトを==で比較すると、オブジェクトの参照を比較します。上記の例でのif文はtruになり、「2つは全く同じオブジェクトを参照しています。」が出力されます。
まとめ
本記事で利用したサンプルケースのクラス図は下記になります。
「Singleton」パターンはクラスのオブジェクトが1つしか生成されないことを保証するパターンです。多用すると思わぬバグが生まれたり、コードの可読性を損なうことにもつながりますが、適切に使えば便利なパターンです。是非参考にしてみてください。
コメント