もっとも頻繁に使われるデザインパターンといえば、Singletonパターンでしょう。
このSingletonパターンには、「インスタンスが1つしか作られないことを保証する」という意味が含まれます。
もちろん開発者が、「このクラスのインスタンスは1つしか作らないように注意!!」とコメントを書いておけば、引継ぎを受けた開発者はそのように注意するでしょう。
ですが、「作らないように注意する」と「作れない」では大きな差があります。
実装方法はとても簡潔で理解しやすい内容なので、特徴やクラス図、Javaでサンプルコードを動作させ、最後にSingletonパターンについての注意点も確認していきましょう。
特徴とクラス図
特徴
見出しでも記載したように「インスタンスが1つしか作られないことを保証する」というデザインパターン。
ソースコードでは以下のような特徴があります。
- 同じ型のインスタンスがprivateなクラス変数として定義される。
- コンストラクタがprivateである。
- インスタンスを返すクラス関数が定義されている。
インスタンスを取得する際にはnewではなく、「インスタンスを返すクラス関数」をコールし、使用することになります。
一般的には、[getInstance()]メソッドとして定義されていることが多いです。
クラス図
singleton、getInstance()についている下線はその要素がstatic(クラスフィールド、クラスメソッド)であることを示します。
また[ – ]、[ + ]はその要素の可視性を示します。
([ – ]はprivate、[ # ]はprotected、[ + ]はpublic、[ ~ ]はpackage)
イテレータパターンやアダプターパターンと比べても簡単に見えます。
Singletonパターンの実装
では実際にソースコードにしていきます。
1 2 3 4 5 6 7 8 9 10 11 |
package com.xoxopigs.singleton; public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() { } public static Singleton getInstance() { return singleton; } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
package com.xoxopigs.singleton; public class Main { public static void main(String[] args) { Singleton obj1 = Singleton.getInstance(); Singleton obj2 = Singleton.getInstance(); if (obj1 == obj2) { System.out.println("2つのオブジェクトは同じインスタンスを指す"); } } } |
実際に動作させてみると「2つのオブジェクトは同じインスタンスを指す」と表示されるように、[ obj1 ]も[ obj2 ]も同じインスタンスを参照していることが分かります。
つまり、インスタンスは1つしか作られないと保証されていることになります。
プロジェクト内で[ Singleton ]クラスがロードされた際に、クラスフィールドであるsingletonインスタンスを作成し、getInstanceで常にこのインスタンスが返るようになっているためです。
Singletonパターンの注意点
「作らないように注意する」ではなく、「作れない」。こういった制限をクラスに加えることはとても大切です。
ですが、ここで「getInstanceメソッドを使用することでコード上のどこであっても同一のインスタンスにアクセスできる。」と考えると、グローバル変数のように動作させることができてしまいます。
そしてグローバル変数が持つ問題点も同様に持つことになります。
そのため、インスタンスが持つデータを変更するような処理を加えてしまうと「どこで変更されたのか分からない。」といった状態になってしまうこともあります。
この点には実装時に特に注意を払う必要があることは覚えておいてください。
まとめ
Singletonパターンは大変便利ですが、注意などにも書いたように一定の問題もはらんでいます。
正しく利用すれば、とても力を発揮するデザインパターンなので、作成するオブジェクトについて分析しSingletonパターンが適応できないか、どんなデータをもつSingletonなのかをよく検討する必要があります。