【Unity】シングルトンを使って1つしか存在しないことを保証すると良いことがあるらしい

シングルトン.png

 Unityでゲーム開発していると、「シーン上に1つしか存在しない(させない)スクリプト」が出てきます。
まぁ普通にFindとかGetComponentしてアクセスすればいいのですが、もっと気軽にアクセスしたくないですか?

 そんな時は「シングルトン」という手法はいかがでしょうか。

「シングルトン」はUnityの固有機能でもなんでもなく、オブジェクト指向のプログラミングにおけるデザインパターンの一種です。「シングルトン」を使うと、クラスのインスタンスが1つしか生成されないことが保証され、FindやGetComponentせずとも1行で簡単にアクセスできるようになります。
シーン上に1つしか存在しない(させない)クラスの例としては、プレイヤー自身のデータを管理するクラスや、ステージの進行を管理するクラスなどが考えられます。

このような各スクリプトから頻繁にアクセスされるようなクラスは「シングルトン」で管理するとびっくりするほど簡単です。
さっそく使ってみましょう。


クラスをシングルトン化する

public class PlayerData : MonoBehaviour
{
// シングルトン
private static PlayerData instance;
public static PlayerData Instance
{
get
{
if (null == instance)
{
instance = (PlayerData)FindObjectOfType(typeof(PlayerData));
if (null == instance) Debug.Log(" PlayerData Instance Error ");
}
return instance;
}
}

void Awake()
{
GameObject[] obj = GameObject.FindGameObjectsWithTag("Player"); //タグで判別
if (1 < obj.Length) Destroy(gameObject);
else DontDestroyOnLoad(gameObject);
}

// ここに処理を書く

}
※隠れているコードは横スクロールで見てください
水色の部分は自身のクラス名やタグ名に置き換えて下さい

private static PlayerData instance;
↑ここで共有したいクラスを宣言しています。

public static PlayerData Instance
{
    get
    {
        略
        return instance;
    }
}
↑get onlyなプロパティからprivate staticのinstanceに戻す。
こうすることで、PlayerDataインスタンスは、instanceプロパティを使って取得できるようになります。
詳しい仕組みは別のブログ様が説明していますので、そちらに譲りますw

さてこれで PlayerData がシングルトン化されました。
このスクリプト(例ではPlayerData.csと命名)をシーン上に配置しましょう。

シングルトン化されたクラスへのアクセス

PlayerData.cs 側にアクセスしたい変数などを用意します。
	public int Gold = 0;
別のスクリプトから Gold にアクセスするには
        PlayerData.Instance.Gold += 100;
と記述するだけでOKです。
めっちゃ簡単じゃないですか??

懸念点がなくはない

一見便利なシングルトンですが、反シングルトン原理主義者というものが多数存在します。
KuroMikanはまだその領域に到達していませんが、有識者の意見を抜粋してみます。

・Singleton と static 結合Singleton は static な結合を招く。インスタンスの数は問題ではない。アクセス方法を static に規定するのが悪。static 結合はテスト不能なクラスへの道。

・Singleton は単体テストの敵。

・まとめSingleton は現代のグローバル変数。結合度が高くテストしにくいコードを招く。SingletonでやりたいことはTyphoon などの DIコンテナを使えば美しく実現できる。

ワタシはSingletonがキライだより引用

「必要なインスタンスは1つだけ」という要望は、多くの場合推測にすぎない。クラスを作った時には「インスタンスは絶対に1つしかいらないだろう」と考えていても、後にそうもいかなくなることが多いのです。

・マルチスレッド環境での使用は特に危険が大きい。マルチスレッドでは、シングルトンオブジェクトへのアクセスにはロックが必要になりますが、単純なロックでは効率が良いとは言えないため、いわゆるDCLP(Double-Checked Lockingパターン)を使うことが増えています。しかし困ったことに、これだと危険性が高まってしまう恐れがあります。多くの言語で、DCLPはスレッドセーフでないということがわかっているからです。

プログラム終了の際には、シングルトンも自動的にクリーンアップされることになります。ただし、複数のシングルトンがある時、どのような順序でクリーンアップされるかは決まっていません。相互に依存し合うシングルトンがアプリケーションに含まれている時、これは問題になります。アプリケーションのシャットダウン時に、あるシングルトンが別のシングルトンにアクセスしようとするけれど、そのシングルトンはすでにクリーンアップされてしまっている、という事態になる恐れがあるからです。

シングルトンパターンの誘惑に負けないより引用

このように、ユニットテストの問題だったり、マルチスレッド環境でのロック方法だったり、終了時におけるシングルトン同士の依存関係の破綻などが懸念されるようです。
シングルトンはめっちゃ便利ですが、無敵ではありません。
上記のような懸念点を考慮の上でプログラミングできればいいですね。


📖このページを見ている方におすすめの書籍📖