デザインパターン: Singletonパターン -たった一つのインスタンス-
はじめに
GoFの23のデザインパターンがまとめられている「Java言語で学ぶデザインパターン入門」を読んでアウトプットとしてデザインパターンを1つずつ記事としてアウトプットしていきます。
原則的にJavaで実装コード例などを記述していきますが、気になったことや改善点、感想等ありましたらぜひコメントくださると嬉しいです!
23のパターン一覧はこちらから ※随時更新中
1.Iteratorパターン
2.Adapterパターン
3.Template Methodパターン
4.Factory Methodパターン
5.Singletonパターン
6.Prototypeパターン
7.Builderパターン
8.Abstract Factoryパターン
9.Bridgeパターン
10.Strategy
11.Compositeパターン
12.Decoratorパターン
13.Visitorパターン
14.Chain of Responsibilityパターン
15.Facadeパターン
16.Mediatorパターン
17.Observerパターン
18.Mementoパターン
19.Stateパターン
20.Flyweightパターン
21.Proxyパターン
22.Commandパターン
23.Interpreterパターン
Singletonパターンとは
Singletonパターンのイメージ
生成に関するデザインパターンの一つで、「Singleton」パターンとは「クラスのインスタンスが1つしか生成されないことを保証する」パターンです。
「Singleton」は直訳すると「単一の」という意味があります。Javaのクラスはオブジェクトの設計図であり、その設計図から複数のインスタンスを生成することができます。しかし、「Singleton」では絶対に一つのインスタンスしか作られないようにするパターンです。
Singletonパターンの使いどころ
アプリケーション内の設定を行うクラスや、ログを収集するクラス等で活躍することができます。
マイナンバーカードのイメージ
設定を行うオブジェクトを複数生成できてしまうと、最初に生成した設定と後から生成した設定が違うものになり、バグの温床となります。また、ログを出力するクラスのオブジェクトが複数生成できてしまうと、出力先の不一致や、出力順序の競合などの可能性があります。このような場合に「Singleton」パターンを利用するといいでしょう。
<!-- しかし実はSingletonには罠が潜んでします。それはまた別のお話で...
https://zenn.dev/articles/4c5624c79ab4dd/edit -->
実装例
ではサンプルを交えて実装方法を紹介します。マイナンバーカードの例をあげてみましょう。
マイナンバーカードは「Singleton」のパターンだと言えるでしょう。個人のデータ自体は別のところに保存されていますが、個人に交付されるマイナンバーカードは絶対に1枚です。2枚交付されることは決してなく、マイナンバーカードの有効期限が切れたとしても、この世に自分のマイナンバーカードは1枚しかありません。
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()**メソッドを作成します。このメソッドはpuplicなメソッドなため外部から利用が可能です。
それでは本当に一つのインスタンスしか生成されていないかを動作確認してみましょう。
Card card1 = Card.getInstance();
Card card2 = Card.getInstance();
Card card3 = Card.getInstance();
if (card1 == card2) {
System.out.println("1と2は全く同じオブジェクトを参照しています。");
}
if (card2 == card3) {
System.out.println("2と3は全く同じオブジェクトを参照しています。");
}
if (card1 == card3) {
System.out.println("1と3は全く同じオブジェクトを参照しています。");
}
出力結果
1と2は全く同じオブジェクトを参照しています。
2と3は全く同じオブジェクトを参照しています。
1と3は全く同じオブジェクトを参照しています。
試しに3つのインスタンスを生成してみましたが、出力結果から全て同じインスタンスであることがわかりますね。
まとめ
Singletonパターンとは
「Singletonパターン」とは「クラスのオブジェクトが1つしか生成されないことを保証する」パターンで、アプリケーションの設定をしたり、ログを出力するクラスのオブジェクトなどに使うと効果を発揮します。
本記事で利用した「Singleton」のクラス図は下記になります。
「Singleton」は開発を進めていく段階で思わぬバグが生まれたり、コードの可読性を損なうことにもつながりますが、適切に使えば便利なパターンです。是非参考にしてみてください。
Discussion