この記事でのバージョン
Unity 5.3.4f1 Personal
はじめに
さて、今回はシングルトンなクラスのお話。
そもそもシングルトンとは、以下のようなデザインパターンの一つです。
Singletonパターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。
何かを管理するマネージャークラスなど、インスタンスが複数あると困る場合に使われる手法で、
MonoBehaviourがStaticにできないため、Unityでもよく使われます。
今回は上記記事を参考に、自分なりにシングルトンなクラスを作成してみました。
なお、タイトル通りAwakeやStart以外に初期化メソッドを備えています!
SingletonMonoBehaviour
早速コードから!
なお、ジェネリックってなんぞ?な方はこちらの記事を読むとよりわかり易いと思います。
このSingletonMonoBehaviourを継承することで、シングルトンパターンのクラスを実装できます。
using UnityEngine; public class Manager : SingletonMonoBehaviour<Manager>{ //初期化メソッド(初アクセスまたはAwake時のどちらか一度だけ実行される) protected override void Init(){ base.Init (); /*初期化処理を色々と*/ } }
使い方は以下のような感じで、
Instanceにアクセスすることで、メソッドの実行などが行えます。
Manager.Instance.Hoge();
他のクラスからFindでインスタンスを探す必要もありませんし、
Inspectorからアタッチする必要もありません。
しかも初アクセス時またはAwake時にインスタンスを生成し、初期化するので
いつアクセスしても大丈夫!
ただし、シーン内に二つ以上存在する時やシーン内に存在しないのにアクセスするとエラーになります。
エラーでなく、片方を削除したり、新しく生成した方がいいんですかね?要検討。
Awakeは使わない
SingletonMonoBehaviourの初期化処理はAwakeではなくInitで行います。
なお、InitはAwake時かその前の初アクセス、どちらか一度しか行われません。
間違って初期化処理を書かないように
Awakeはsealedしてるので、継承先でoverrideするとエラーが出ます。
まぁ、overrideしなきゃ普通に使えちゃうんですけどね……。
Init
そもそも、なんでInitがあるかという所なんですが、
「アクセスした時に初期化が必ず完了してるため、いつでもアクセスできる」
という実装にしたかったからです。
参考記事のようにAwakeでもアクセス可能なものはありますが、
この時、シングルトン側のAwakeに初期化処理が実装されていて、かつ、Awake前にアクセスすると、
シングルトン側の初期化処理が済んでいないことになります。
なので、結局Awake以降(Startとか)にアクセスしなくてはならなくなるので、
そこを改良しようとしたらこのような形になりました。
静的コンストラクタ
初期化に静的コンストラクタを使う方法も考えたのですが、
あまりUnityでの開発時に使われてなさそうなので試してません。
コンストラクターの代わりに Awake を使用してください。これはコンポーネントの serialized ステートはコンストラクト時点では定義されていないためです。
初期化に静的コンストラクタを呼ぶと死ぬ。エディタでは死ななくてもビルド後のiOSとかAndroidとかで死ぬ。
おわりに
Overrideを使わなければ継承先でAwakeを使えたり、
初期化処理のためだけでにMonoBehaviourWithInitというクラスを作っていたり、
納得のいった形ではないのですが、自分の力ではこれが精一杯でした……。
なにかもっと良い方法があればご一報を!
------追記
全てのシーンに存在し、かつ、一つしかいないマネージャー的な存在
の実装方法についても記事にしたので、こちらも参考にどうぞ!