Dependency Injection with Singleton classes

Referencing other classes: From manual labour through the Inspector to automatic firing via writing Singleton classes

Passing references between classes is like building bridges, isn't it?

Say that you write a new script, that has to get a reference to some other script when it starts. In other words, you are writing a new script (say that it implements class A inheriting from MonoBehaviour), that in its Start method has to get a reference from another MonoBehaviour script (say class B) and call one of B's methods (say Hello). This procedure is also called as 'Dependency Injection', you may find a nice explanation that discusses the use of software patterns here. How to do that in a silly, simple and straight-forward way? And then, how to do that auto-magically?

The ordinary way: Using Public Variables


The simpler and recommended way to do this in Unity is through the use of a public variable:

Script A.cs:

using UnityEngine;
public class A : MonoBehaviour {
         public B bReference;

         void Start () {
                  bReference.Hello();
         }
}


Script B.cs

using UnityEngine;
public class B: MonoBehaviour {
         public void Hello() {
                   Debug.Log("Hello from class B");
         }
}

After writting the scripts and attaching them on 2 GameObjects in the scene, you would have to pass the reference of B to A by dragging the gameObject where B is attached to to the bReference placeholder of the A script component inside the Inspector of the Unity Editor.

That is all ok and nice and working without fuss, but imagine that you have a bunch of classes referencing each-other, and happening to all instantiate at the start of the scene and stay there until the scene is destroyed? You would have to place by hand all those references in the Inspector. Let me give you an example of such a case:
In at least one game I was working with, there were several classes managing different sectors of the game, e.g. PlayerManager, LevelManager, AudioManager, PersistenceManager. All these classes had to had a way to reference each other, and access each other's methods. This had to be a way of communicating without using the slow 'sendMessage', or using custom events and delegate methods. Manually hard-wiring public variables to reference each class would entail a series of problems when the scene would not be saved correctly on disk, or when the scene would fail to be correctly updated from an Asset Server version update.

The auto-magic way: Using a singleton pattern

Hopefully, there is another alternative for setting automatically one such public reference in the Start method of a MonoBehaviour, but there is a catch: it is appropriate and useful ONLY if class B is a class that follows the Singleton pattern. What is a singleton class you might ask? It is a class that may have only one instance at any time. What is best about this? You can get a valid reference and instantiate the class if there is no instance already through A's Start method in one line of code. Let me show you how:

Script A.cs:

using UnityEngine;
public class A: MonoBehaviour {
         public bReference;

         void Start() {
                   bReference = B.bInstance;
                   bReference.Hello();
         }
}

Script B.cs:

using UnityEngine;
public class B: MonoBehaviour {
         private _instance;
         public static B bInstance {
                  get {
                         if (!_instance) {
                                   GameObject bHost = new GameObject("B_Host");
                                   _instance = bHost.AddComponent<B>();
                         }
                         return _instance;
                  }
         }

        public Hello() {
                    Debug.Log("Hello from class B");
         }
}


The getter on class B does all the work. If there is not an instance already of class B, the private _instance that stores a reference to the one and only instance of B will be null (note that bInstance is declared static, otherwise it will not be accessible outside B when there is no instance of B alive). When class A gets a reference to B through the line 'bReference = B.bInstance;', the get method instantiates class B by creating a new GameObject (named B_Host) and attaching itself by AddComponent to it, and returns bInstance as a public valid reference to itself. That's it.

WORD OF CAUTION: In Unity you should never instantiate classes that inherit MonoBehaviour by the 'new' operator (this is why we did not use '_instance = new B();'). The appropriate method is through a GameObject's AddComponent method. In other words, first find (or create) the game object in the scene where your script will attach to, and then call this object's AddComponent by specifying the component's type, which should be the name of your class.

From that point and on, A will be able to execute any public method of B through its bReference variable. You may better turn bReference private, I left it public in the example above just so that you are able to see the valid reference it gets in the Inspector when this simple example is run.

Where do we go from here?

Dependency injection is far from accomplished at this point, but at least it is partially tackled. In the next series of this post, I will introduce how others have resolved it through Interface classes and by applying a central Factory method software pattern, just like the one I used in this post. Way to go friends!

Comments