First, buckle up. This is gonna be a hell of a ride! [\m/][1]
The singleton pattern is indeed, one of the most miss-used and debated pattern amongst all other patterns.
They say it’s evil, its evilness comes from the fact that most people use it because they’re too lazy to pass their references to their classes, and they feel that it’s easier to just have an easy global access to their variables, which smells like static (no need to say how evil statics are, if they’re misused)
You can read all about what the experts have to say about it (which normally, a lot of us including me don’t give a rat ass about lol), but they all circle around:
- It’s hard to perform tests on singletons.
- They hide your class dependencies.
- What if, at some point in the future you decided that you need another reference of your class?
For more info, see [1][2], [2][3].
So does this mean you shouldn’t use a singleton? - You can use the singleton AS LONG AS YOU DON’T MISS-USE IT!
Why do I mean by that? - Well, singletons exist to give you the ability to have only one instance of your object at a time. They’re NOT meant to be used only to provide easy global access. That’s when you miss-use it.
Would it make sense to make all the classes that should only be used once into a singleton, or is it unnecessary?
Well, it’s definitely not a must. But if for some reason you must have only one instance of your class, if you’re 100% sure that you won’t need more than
one, and you don’t actually care about the global access (sweet-looking) feature, if you see that your object will live throughout your entire application, then by all means, USE IT! ([DO. IT.][4] Gus tone lol) WITHOUT FEAR (especially from those who scare you away from it for no reason). Otherwise, don’t.
I will tell you of some other alternatives in a second, for now here’s a nice Singleton implementation, taken from the [wiki][5], and modified by me so that if you ever had more than one instance of your gameObject
, all the extra instances get destroyed and only one remains:
using UnityEngine;
public class MonoBehaviourSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static object mLock = new object();
private static T mInstance;
public static T Instance
{
get
{
lock (mLock) {
if (mInstance == null) {
// try to find it
T[] instances = FindObjectsOfType(typeof(T)) as T[];
// couldn't find any object
if (instances == null || instances.Length == 0) {
var instanceObj = new GameObject("(Singleton) " + typeof(T));
mInstance = instanceObj.AddComponent<T>();
Debug.Log("[Singleton]: An instance of `" + typeof(T) + "` is needed." +
" So gameObject `" + instanceObj.name + "` was created" +
" with `" + typeof(T) + "` component attached to it");
}
else {
// see if there's more than one, if so, do something about it
if (instances.Length > 1) {
Debug.LogWarning("[Singleton]: There is more than one instance of `" +
typeof(T) +
"` in your scene. Destroying all, keeping only one...");
for (int i = 1, len = instances.Length; i < len; i++) {
Destroy(instances*);*
-
}*
-
}*
-
else if (instances.Length == 1) {*
-
Debug.Log("[Singleton]: Found only one instance of `" +*
-
typeof(T) +*
-
"` in `" + instances[0].gameObject.name +*
-
"` So singlation successful! :)");*
-
}*
-
mInstance = instances[0];*
-
}*
-
DontDestroyOnLoad(mInstance); // for preservation of this object through scenes*
-
}*
-
return mInstance;*
-
}*
-
}*
-
}*
-
public void Ping()*
-
{*
-
Debug.Log("[Singleton]: `" + this + "` is alive!");*
-
}*
-
protected virtual void Awake()*
-
{*
-
Ping(); // this is just so that DontDestroyOnLoad gets called on the gameObject that's gonna this script upon waking up - Calling Ping means accessing the singleton instance, doing so calls DontDestroyOnLoad at the end.*
-
}*
- }*
As you can see what’s nice about this implementation, is that it inherits from MonoBehaviour
so you can enjoy coroutines, etc. The other cool thing as I mentioned, is that if more than one instance is found, all die but one. You don’t have to worry about nulls. And it’s also thread-safe.
USAGE:
public class GameController : MonoBehaviourSingleton
{
// …
}
Now from anywhere else you can: GameController.Instance.doStuff();
- If doStuff
is called regularly, you could avoid a few keystrokes by introducing a static method in your GameController
:
void static void DoStuff()
{
Instance.doStuff();
}
Now you can immediately: GameController.DoStuff();
So far I have no problems using this system whatsoever (From a not-very-long-time usage perspective)
FURTHER AWESOME REASONS TO USE THE SINGLETON:
- Everybody is doing it.
- The singleton pattern makes you
invincible.
- Singleton rhymes with “win” (or “fun”
depending on your accent).
([from][6])
----------
Now that we’re done with that, let me introduce you to the first alternative, a new product, a product that will change your life ([it’s beer, huehue hueheu hue][7]): It’s Mr.Fattie’s almighty super awesome immortal Grid system (@Fattie)
Take a look at it [here][8].
Now, I was actually intending to open up a large question related to Singletons and this system, but I couldn’t have the time. But since I wanted to do that, I went ahead and made a clean, nice implementation of Mr.Fattie’s system, I renamed it Container
which I think is more expressive in terms of the meaning:
- using UnityEngine;*
- public static class Container*
- {*
-
public static AtlasManager AtlasManager { private set; get; }*
-
public static GameController GameController { private set; get; }*
-
public static InventoryManager InventoryManager { private set; get; }*
-
// insert more stuff here...*
-
public static GameObject HoldAll { private set; get; }*
-
static Container()*
-
{*
-
HoldAll = SafeFindWithTag(Tags.holdAll);*
-
Object.DontDestroyOnLoad(HoldAll);*
-
AtlasManager = Add(AtlasManager);*
-
InventoryManager = Add(InventoryManager);*
-
GameController = Add(GameController);*
-
// when you insert something new, don't forget to Add it*
-
}*
-
private static GameObject SafeFindWithTag(string tag)*
-
{*
-
var GO = GameObject.FindWithTag(tag);*
-
if (GO == null)*
-
ThrowError("[Container]: GameObject of tag `"*
-
+ tag*
-
+ "` was not found!");*
-
return GO;*
-
}*
-
private static void ThrowError(string msg)*
-
{*
-
Debug.LogError(msg);*
-
Debug.Break();*
-
}*
-
private static T SafeGetComponent<T>(GameObject from) where T : Component*
-
{*
-
T comp = from.GetComponent<T>();*
-
if (comp == null)*
-
ThrowError("[Container]: Component `"*
-
+ typeof(T)*
-
+ "` was not found in the GameObject `"*
-
+ from.name);*
-
return comp;*
-
}*
-
private static T SafeGetComponent<T>() where T : Component*
-
{*
-
return SafeGetComponent<T>(HoldAll);*
-
}*
-
public static T Add<T>(T member) where T: Component*
-
{*
-
Object.DontDestroyOnLoad(member);*
-
return SafeGetComponent<T>();*
-
}*
-
public static void Ping(GameObject go)*
-
{*
-
Debug.Log("[Container]: Hear you loud and clear, `" + go.name + "`");*
-
}*
-
public static void Ping()*
-
{*
-
Debug.Log("[Container]: Everything's working fine. IT'S ALIVE!");*
-
}*
- }*
As you can see it’s all clean, you got generics going on, minimal code and ease of usage.
USAGE:
1. Let’s say you wanted to add an
AudioManager
to your game, you
first create the AudioManager
class, attach it to a gameObject.
2. Once you do that, you now come to the Container
, and add a static property like you see above for your AudioManager
- and add it to the system using AudioManager = Add(AudioManager);
Which will add it to HoldAll
(I will explain about it in a sec)
3. Now you can enjoy Container.GameController.DoStuff();
(you can do the same static trick I did in the singleton to reduce keystrokes)
One thing I haven’t mentioned, is the HoldAll
idea. What you do is, to have a gameObject
called HoldAll
whose soul purpose is to hold persistence data (like managers, controllers and whatnot ) across scenes.
You would create this gameObject
in a scene, on its own! a Pre_Game
scene, from that point you have your data with you, and you can travel between your scenes with your data carried with you. But just make sure that the user don’t have the ability to later come back to this scene, cause a lot of users had problems with that in that they had duplicates of the HoldAll
object, so they go around it creating counter-measures (Mr Fattie’s new favorite word) by attaching scripts, that checks if they’re more than one object, the other gets destroyed, etc. I personally don’t find a reason for that, I just don’t go back to that scene and that’s it.
A good idea, would be to have a simple script attached to your HoldAll
gameObject, that simply does this:
- void Start()*
- {*
-
Container.Ping(); // must bring it alive before loading anything game-related*
-
Application.LoadLevel(1);*
- }*
And that’s it really, you start with your PRE_GAME
scene, you Ping
the Container
just to bring it alive thus calling DontDestroyOnLoad. (Recall that, Container
has a static constructor, and that gets only called when you access anything in the Container
, that’s why Ping
is enough for us)
Of course, this HoldAll
idea isn’t restricted to the Container
system, in fact you should always use it (or something similar) to preserve/ keep your persistent data alive.
This Container system works really great, I haven’t found any issues with it. [Yeah Mr.Fattie, yeah Grid!][9]
I can’t really compare it with the Singleton
implementation I gave you because I don’t have enough experience with either of those.
Oh and, almost forgot, the Tags
mentioned above (in Tags.holdAll
) is just a class I always use to manage my tags:
public static class Tags
{
public const string holdAll = “HoldAll”;
// … add new tags as you move along
}
The const
keyword makes the variable kinda static, and constant at the same time (you can’t change it) - So you could access the tags like Tags.Player
, etc.
----------
The final alternative I know about, is Mr.Jamora’s Monostate
idea, found [here][10]. (@Jamora)
I haven’t got the time to test it unfortunately, but I could tell you a couple of differences between it and the singleton. But first take a look at [this][11], to see how it’s implemented at its core (nice article btw). Now for the differences:
- SINGLETON:
- Only one
instance! (Max one
object)
- Creational pattern.
- Needs to be threadsafe!
- Tough to inherit something.
- Lazy initialization.
- MONOSTATE:
- Only one
state! (You could have
more than one object, but all have
the same state)
- Behavioral pattern.
- Constructor is already thread-safe.
- Could easily inherit.
- Need to new up an object.
([Source][12])
I hope that was helpful to you, and to others investigating the matter in the future.
-V “Whether you think you can do it or not, you’re right in both cases ;)”
----------
EDIT:
Just came across a very nice well-written [book][13] about design patterns in games. [Here’s][14] the singleton part (Amazing stuff). I really liked every part in that book.
----------
EDIT:
Came up with a new system, “Verfices” - [Check it out][15] 
[1]: Annihilator - Time Bomb - YouTube
[2]: What are drawbacks or disadvantages of singleton pattern? - Stack Overflow
[3]: design patterns - Are Singletons really that bad? - Stack Overflow
[4]: http://suggestashow.com/blog/wp-content/uploads/2012/10/2-gus-fringe.jpg
[5]: http://wiki.unity3d.com/index.php?title=Singleton
[6]: language agnostic - Singletons: good design or a crutch? - Stack Overflow
[7]: - YouTube
[8]: How can I instantiate a prefab from a static function? - Unity Answers
[9]: YEAH SCIENCE - YouTube
[10]: Level Independant Data - Unity Answers
[11]: The Monostate pattern - Simple Thread
[12]: Redirect Notice
[13]: Game Programming Patterns
[14]: Singleton · Design Patterns Revisited · Game Programming Patterns
[15]: http://forum.unity3d.com/threads/210080-quot-Verfices-quot-a-well-written-clean-documented-and-optimized-global-access-system!