デザインパターンとは?
デザインパターンとは、Unity
に限らずソフトウェア開発全般において使われる、設計の定石です。
「こういう問題に対して、こう設計すればうまくいく」という経験則から生まれたテンプレートのようなもので、
プログラミング言語に依存せず幅広く活用する事が出来ます。
ただ言語によっては、デザインパターンをより簡単に実装出来たり、逆に複雑になる場合もあります。
シングルトン(Singleton)
シングルトンパターンとは、アプリケーション全体でただ一つだけのインスタンスを保証し、どこからでもアクセスできるグローバルなアクセスポイントを提供するデザインパターンです。
例えば、
GameManager
SoundManager
- セーブデータ管理
などどのシーンからでもアクセス出来、必ず一つだけ存在すべきクラスに使われます。
Unityにおけるシングルトンの例(MonoBehaviour)
よく見かける実装ですが、例えば以下の様なクラスです。
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance == null)
{
Instance = this;
// DontDestroyOnLoadに指定し、シーンを跨いでも破棄されないようにする
DontDestroyOnLoad(gameObject);
}
else
{
// 後から生成されたインスタンスは破棄する
Destroy(gameObject);
}
}
public void StartGame()
{
Debug.Log("Game Started");
}
}
このGameManager
がシーン上のGameObject
にアタッチされていると、
Awake
メソッドでInstance
に現在のGameManager
が代入されます。
その後のDontDestroyOnLoad
でシーンをまたいでも破棄されず存在し続けるようになります。
それ以降に別のGameManager
を作ろうとしても、既にInstance
が代入されているため、
後から生成されたインスタンスは全てDestroy
されます。
これによりどのシーンやコンポーネントからでも以下のようにメソッドを呼び出すことが出来るようになります。
GameManager.Instance.StartGame();
MonoBehaviourを継承しない場合のシングルトン
MonoBehaviour
を継承しない純粋なC#
クラスの場合は、以下の様に書けます。
public class SoundManager
{
public static SoundManager Instance => _instance ??= new SoundManager();
private static SoundManager _instance;
// プライベートコンストラクタを使用して、外部からのインスタンス化を防ぐ
private SoundManager()
{
}
public void PlaySound(string soundName)
{
Debug.Log($"Playing sound: {soundName}");
}
}
コンストラクタをprivate
にしているので、外部から直接インスタンスを生成することはできません。
また、Instance
プロパティでは??=
演算子を使用しており、
_instance
がnull
の場合のみ新しいインスタンスを作成し、
それ以外は既存のインスタンスを返すようになっています。
これにより、Instance
プロパティを通してアクセスする限り、
いつでも同一のインスタンスを参照できるようになります。
シングルトンの注意点
一見便利そうなシングルトンですが、いくつか注意点があります。
依存性が分かりにくくなる
依存性を隠してしまうため、コードの可読性や保守性を下げる原因となる場合があります。
結合度が高くなる
他のクラスがシングルトンクラスに依存するので、コードの変更が波及しやすくなります。
責任が集中しがち
1つのインスタンスが何でもやる状態になりがちです。
うまく責任を分散することを意識しましょう。
再利用性、拡張性が低い
固定的なインスタンスとなるため、後から継承や差し替えが難しいことがあります。
初期化のタイミングが不明瞭
MonoBehaviour
を継承している場合、Awake()
の実行順に依存しやすく、
他のオブジェクトがシングルトンにアクセスしようとした時にまだ初期化されていない可能性があります。
Script Execution Order
で順序を制御するか、遅延初期化などの対策が必要になる場合があります。
まとめ
今回は、デザインパターンのひとつである「シングルトンパターン」について解説しました。
Unity
では MonoBehaviour
を使ったシングルトン実装をよく見かけますし、
ミドルウェアや各種管理クラスなど、実際のプロジェクトでも頻繁に利用されています。
どこからでも同じインスタンスにアクセスできるのは非常に便利ですが、
その反面、注意しなければならない落とし穴も存在します。
便利だからといってなんでもシングルトンにしてしまうのではなく、
本当にその設計が適切か検討した上で、慎重に選択していきましょう。
📣おしらせ!
Unity Asset StoreでICONIC ESSENTIALS SALEが開催中です。 日替わりでお得なアセットが登場します。