Singleton
神:人間からは干渉できないもの
絶対不変であり、どの人間にとっての共通の認識を持つ
その必要条件は
- 2度目以降に呼び出されると1度目と同じ実態を返す
- イミュータブルである
こと。
やり方
- コンストラクタをprivateにする
- 唯一のpublic staticなインスタンス生成メソッドを作成し、その中で一度だけ生成したインスタンスを返す
マンガでわかる Singleton
マンガでわかる Singleton #デザインパターン - Qiita
でざぱたんで覚える Singleton
ちびキャラは「シングルトンたん」。OOP王国の女王で、「王の責と業を負う者など、ひとり居れば充分」。システム中に一個だけのインスタンスを保証するのがSingletonだが、本書は「要するに絶対唯一君臨するグローバル変数」と身も蓋もなく言い切り、privateコンストラクタゆえにmockが作れず単体テストを壊しがち、と釘を刺す。便利さと引き換えの「王政」のリスクまで含めて覚えたい。
出典: いしだけ『でざぱたん: ちびキャラで覚えるデザインパターン』(P.142〜)
クラス図
このサイトの実装での対応関係:
classDiagram
class Singleton {
-singleton Singleton
-Singleton()
+getInstance() Singleton
}
Singleton --> Singleton : holds the sole instance
メリット
クッソ重いインスタンスがアプリケーション内に一つしか生成されないことを約束できるので、メモリ節約になる
同時に複数インスタンスを管理しなくて良くなるので予期せぬバグを防げる
関連
これらのパターンはインスタンスが1つであることが多い
Java
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
System.out.println("インスタンスを生成しました。");
}
public static Singleton getInstance() {
return singleton;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if (obj1 == obj2) {
System.out.println("obj1とobj2は同じインスタンスです。");
} else {
System.out.println("obj1とobj2は同じインスタンスではありません。");
}
System.out.println("End.");
}
}
Go
Goに private constructor は無い。代わりに「型を非公開(singleton)にして、生成口を GetInstance() だけに絞る」で唯一性を守る。sync.Once で遅延&スレッド安全に初期化(Javaの即時初期化に近い「パッケージ変数の即時初期化」も別解としてコメント併記)。
実行: go run ./GoF/patterns/Singleton/go
package main
import (
"fmt"
"sync"
)
// singleton は型名を小文字にして「外部パッケージから勝手に生成させない」を表現する。
// Go には private constructor が無いので、
// - 型を非公開(singleton)にする
// - 生成手段を GetInstance() だけに絞る
//
// の組み合わせで唯一性を守るのが定番。
type singleton struct {
// 状態を持たせるならここに。今回は存在確認だけなので空。
}
var (
instance *singleton
once sync.Once
)
// GetInstance は唯一のインスタンスを返す。
// sync.Once により初回だけ生成し、以降は同じものを返す。
// 複数の goroutine から同時に呼ばれても生成は一度きり(スレッド安全)。
func GetInstance() *singleton {
once.Do(func() {
fmt.Println("インスタンスを生成しました。")
instance = &singleton{}
})
return instance
}
// 【別解】遅延生成が不要なら、パッケージ変数の即時初期化が最短:
//
// var instance = &singleton{}
// func GetInstance() *singleton { return instance }
//
// Java版の「private static Singleton singleton = new Singleton();」に一番近いのはこちら。
// パッケージ変数の初期化はプログラム起動時に一度だけ走るので、これも安全。
package main
import "fmt"
// 実行: go run ./GoF/patterns/Singleton/go
//
// 「インスタンスを生成しました。」が一度しか出ないこと、
// obj1 と obj2 がポインタとして等しいことで、唯一性を確認する。
func main() {
fmt.Println("Start.")
obj1 := GetInstance()
obj2 := GetInstance()
if obj1 == obj2 {
fmt.Println("obj1とobj2は同じインスタンスです。")
} else {
fmt.Println("obj1とobj2は同じインスタンスではありません。")
}
fmt.Println("End.")
}
PHP
<?php
/**
* 絶対唯一君臨するグローバル変数
* システム中に一つだけあれば良い、または一つしかいて欲しくない
* インスタンスを制御するためのパターン
* 生成が重くて至る所でnewさせちゃいけないとき
*/
/**
* ログや設定ファイル、重いオブジェクトなど
* その実態を使いまわしたいときに用いる
* やり方
*
* 1. コンストラクタをprivateにする
* 2. 自身を保持するprivate staticな変数を作成する
* 3. 自身を返す public staticなメソッドを作る
*
*
*/
class Singleton
{
private static $instance;
/**
* 外部からnewできないようにコンストラクタを
* privateで実装
*/
private function __construct()
{
}
/**
* インスタンスが生成されていなければnew、
* されていればそのままインスタンスを返す
*/
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new Singleton();
}
return self::$instance;
}
}
$obj1 = Singleton::getInstance();
$obj2 = Singleton::getInstance();
if ($obj1 === $obj2) {
print "同じオブジェクトだ";
} else {
print "違うオブジェクトだ";
}
TypeScript
TypeScriptにもprivateコンストラクタはあるが、クラス自体は公開のまま。生成口をgetInstance()だけに絞ることで唯一性を守る(モジュールスコープの単一オブジェクトという手もあるが、Java版により忠実な形にしている)。
実行: npx tsx GoF/patterns/Singleton/typescript/main.ts
// Singleton パターン: 唯一のインスタンス (Java版と同じ題材)
//
// 実行:
// npx tsx main.ts
//
// 「インスタンスを生成しました。」が一度しか出ないこと、
// obj1 と obj2 が===で等しいことで、唯一性を確認する。
// TypeScriptにはJavaのprivateコンストラクタがそのまま存在する(コンパイル時チェックだが実用上十分)。
// 「privateコンストラクタ + static instance + static getInstance()」で唯一性を守るのが
// Java版に最も近い書き方。
class Singleton {
private static instance: Singleton | undefined;
private constructor() {
console.log("インスタンスを生成しました。");
}
// 遅延生成: 呼ばれるまでインスタンスを作らない(Go版のsync.Once版と同じ発想)。
static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// 【別解1】Java版の「private static Singleton singleton = new Singleton();」に一番近いのは即時初期化:
//
// class Singleton {
// private static readonly instance: Singleton = new Singleton();
// private constructor() { console.log("インスタンスを生成しました。"); }
// static getInstance(): Singleton { return Singleton.instance; }
// }
//
// staticフィールドの初期化式はクラス定義の評価時に一度だけ走る
// (モジュールはimport先で一度しか評価されないので安全)。
//
// 【別解2】モジュールスコープの単一オブジェクトをそのままexportする:
//
// class SingletonImpl { ... }
// export const instance = new SingletonImpl();
//
// ESモジュールは一度しか評価されずimport先で共有されるため、
// 「クラス+getInstance()」という器すら要らず、モジュール自体がシングルトンとして機能する。
// これがJS/TSでもっとも慣用的な形。
function main(): void {
console.log("Start.");
const obj1 = Singleton.getInstance();
const obj2 = Singleton.getInstance();
if (obj1 === obj2) {
console.log("obj1とobj2は同じインスタンスです。");
} else {
console.log("obj1とobj2は同じインスタンスではありません。");
}
console.log("End.");
}
main();
Python
Pythonの慣用としては「モジュール自体がシングルトンとして機能する」書き方もあるが、Java版に忠実に、クラス変数でインスタンスを保持しget_instance()で返す形にしている。
実行: python3 GoF/patterns/Singleton/python/main.py
"""Singleton パターン: 唯一のインスタンス (Java版と同じ題材)
実行:
python3 main.py
「インスタンスを生成しました。」が一度しか出ないこと、
obj1 と obj2 がis演算子で同一であることで、唯一性を確認する。
"""
from __future__ import annotations
class Singleton:
"""Java版の「private static Singleton singleton」+「public static getInstance()」を
クラス変数(_instance)とクラスメソッド(get_instance)で再現する。
Pythonにはprivateコンストラクタという言語機能がない(先頭アンダースコアは
「触るな」という慣習に過ぎず、Singleton()を直接呼べば実際に生成されてしまう)。
Java版のような強制力はないので、「get_instance()経由でしか使わない」という
規約で唯一性を担保する — Go版がコメントで書いている「型を非公開にする」代わりに、
Pythonでは命名規約と設計意図のドキュメント化で守る、という対比になる。
【別解1】モジュール自体をシングルトンとして使う
Pythonのモジュールはimport時に一度だけ実行されキャッシュされる。
そのためモジュールレベルの関数・変数がそのままシングルトンとして機能し、
クラスすら要らない。これがPythonでもっとも慣用的な形。
【別解2】__new__をオーバーライドしてインスタンス生成そのものを差し替える
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
こうすると Singleton() を直接呼んでも同じインスタンスが返るようになり、
「コンストラクタを隠す」ではなく「コンストラクタの中身を唯一性チェックにすり替える」
という発想でJava版のprivateコンストラクタに近づける。
"""
_instance: "Singleton | None" = None
def __init__(self) -> None:
print("インスタンスを生成しました。")
@classmethod
def get_instance(cls) -> "Singleton":
# 遅延生成: 呼ばれるまでインスタンスを作らない(Go版のsync.Once版と同じ発想)。
if cls._instance is None:
cls._instance = cls()
return cls._instance
def main() -> None:
print("Start.")
obj1 = Singleton.get_instance()
obj2 = Singleton.get_instance()
if obj1 is obj2:
print("obj1とobj2は同じインスタンスです。")
else:
print("obj1とobj2は同じインスタンスではありません。")
print("End.")
if __name__ == "__main__":
main()