【PHPで学ぶデザインパターン入門】第7回 Singletonパターン


【PHPで学ぶデザインパターン入門】第7回 Singletonパターン

こんにちは、王です。
【PHPで学ぶデザインパターン】第7回はSingletonパターンのご紹介となります。

おそらく最も知られているデザインパターンではないでしょうか。
知っている方も多いと思うので、そういう意味でも実践的なデザインパターンです。名前こそ難しそうに聞こえますが、度肝を抜かれるほどシンプルなパターンです。

Singletonパターンとは

まずは、どんなパターンなのか説明していきたいと思います。

定義

Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならない仕組みの実装に使用される

引用元:Singleton パターン – Wikipedia

Singletonとは「一人っ子」とか「単一の〜」という意味ですから、ここでは「1つしか生成されないインスタンス」という意味合いになります。

どんな場面で使うの?

アプリケーションで同じクラスのインスタンスを複数生成したら不都合なことが起きるような場合に使います。
または、インスタンスの生成にコストがかかる場合など、プログラム実行中にインスタンスを1つだけ生成して、プログラム全体で使い回したいときにも使います。

実装コード

インスタンスを1つしか作らないクラスをどうやって作るの?」と不思議に思うかもしれませんが、実は簡単です。

class Singleton {
	/** @type  Singleton */
	private static $uniqueInstance;

	// コンストラクタを`private`にすることで、他のクラスが勝手にインスタンスを作ることを不可能にする。
	private function __construct() {
		echo '初回のインスタンス化<br>';
	}

	// クラスメソッドでインスタンス化して、オブジェクトを返す
	public static function getInstance() {
		if ( ! isset( static::$uniqueInstance ) ) {
			static::$uniqueInstance = new Singleton();
		}

		return static::$uniqueInstance;
	}

	public function describe() {
		echo 'object_id: ' . spl_object_hash( $this ) . '<br>';
	}
}

$obj1 = Singleton::getInstance();
$obj2 = Singleton::getInstance();
$obj3 = Singleton::getInstance();

$obj1->describe();
$obj2->describe();
$obj3->describe();

出力結果

初回のインスタンス化
object_id: 0000000027a6907d000000012e0071f9
object_id: 0000000027a6907d000000012e0071f9
object_id: 0000000027a6907d000000012e0071f9

ご覧の通り、“new”キーワードを使う代わりに、“Singleton::getInstance()”を使ってインスタンスを取得しています。インスタンス化は1回しか行われないため、“初回のインスタンス化”も初回以降の出力はなかったのが見て取れると思います。

インスタンスを取得するメソッドを3回呼びましたが、みんな同じオブジェクトIDを持っているので、同一オブジェクトが毎回返されているということも確認できますよね。

クラス図

singleton

コンストラクタを“private”とすることで、外部からインスタンスを生成できないようにしているところ以外は特筆すべきところはないと思います。

まとめ

いかがでしたか? 実にシンプルなパターンですよね。
JavaScriptの場合だと、もはやリテラルオブジェクト自体がいわゆるSingletonになっていますよね(笑)
Singletonパターンが世間に広く認知されたのは、そのシンプルさ、強力さ、わかりやすさだと思います。しかし、手軽に使える反面、陥りやすい弊害も多くある諸刃の剣です。

陥りやすい弊害については、参照ページをご覧ください。

参照ページ:Singleton何が悪いの? – Qiita

ケース・バイ・ケースで計画的に利用するのがいいと思います。

それでは、また。

 

【PHPで学ぶデザインパターンシリーズ】

【PHPで学ぶデザインパターン入門】第1回 Strategyパターン

【PHPで学ぶデザインパターン入門】第2回 Decoratorパターン

【PHPで学ぶデザインパターン入門】第3回 Stateパターン

【PHPで学ぶデザインパターン入門】第4回 Iteratorパターン

【PHPで学ぶデザインパターン入門】第5回 Factoryパターン

【PHPで学ぶデザインパターン入門】第6回 Observerパターン

王
この記事を書いた人

バックエンドエンジニア

関連記事