QA@IT

Singletonパターンの実現方法は?

6149 PV

引き続き初心者質問です。

ゲーム内でグローバルな状態を保持するためにシングルトンオブジェクトが欲しいと思って以下のようなコードを書きました

using UnityEngine;

public sealed class Singleton : MonoBehaviour {
    static readonly Singleton instance = new Singleton();
    static Singleton() { }
    Singleton() { }
    public static Singleton Instance {
        get {
            return instance;
        }
    }
}

このコードはコンパイルは通るのですが、実行してみるとConsole欄に

You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed.

と表示されてしまいます。どうやらだめなようです。とはいえゲーム内状態を保存することくらいは普通に行われると思うので、シングルトンが使えないというのも考え辛いのですが、なにか他のよい実装法方があるのでしょうか?

回答

シングルトンの実装は間違ってないと思います。
マルチスレッドなどを考えると、他のやり方もあるのですがこのやり方は間違ってはいません。
(Unityをよく知らないので、このクラスが同時に多スレッドから参照されたりするのかはわかりません。なのでその辺には触れないでおきます。)

エラーメッセージを読むと(おおよそ)『「MonoBehaviour」クラス(を継承したクラス)は「new」できません。』となっています。つまり、そのクラスのインスタンスは作れないことになっています。
おそらくそのクラスを継承しなければシングルトンで作れると思います。

編集 履歴 (0)
  • MonoBehaviourは処理的にどうしても必要なのですよね。 -
  • データのみを保存するシングルトンのクラスと、それを使うためのMonoBehaviourを継承した一時的に生成するクラスに分けるのが得策だと思います。 -
  • なるほど。それはたしかに正論ですね。モデルとコントローラの分離! やってみます。 -

自分はこんな感じでやってます

public class Hoge : MonoBehaviour {
static Hoge instance;
public static Hoge GetInstance(){
return instance;
}
void Awake(){
instance = this;
}
}

UnityのMonoBehaviour を継承したクラスは、コンポーネントというUnityのGameObjectにアタッチするための特殊クラスになります。
コンポーネントは、アタッチしたGameObjectが作成されるまでは初期化されないため、本来シングルトンとちがい、アクセスするタイミングに制限がでてくることになります。
void Awake() は、GameObjectが作成されたときに呼ばれるUnity標準のメソッドです。
ただし、Awake()はGameObjectのenableがfalse(オブジェクトのインスペクター左上のチェックボックスがOFF)だと呼び出されないため、注意してください。

編集 履歴 (0)
編集 履歴 (0)
  • んー、AddComponentするということはこのシングルトンを初期化する際にGameObjectオブジェクトがすでに存在しないといけないはずなので、ということはオブジェクトの初期化に依存関係がでてくるということですねえ。ちゃんとロックをとったりしないといけなそうですねえ。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。