Singleton

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Added another singleton implementation :))
m (Text replace - "<csharp>" to "<syntaxhighlight lang="csharp">")
Line 18: Line 18:
 
Members of both singleton types are accessed the same way:
 
Members of both singleton types are accessed the same way:
  
<csharp>MySingleton.Instance.MySingletonMember;</csharp>
+
<syntaxhighlight lang="csharp">MySingleton.Instance.MySingletonMember;</csharp>
  
 
== The non-component example ==
 
== The non-component example ==
<csharp>public class MySingleton
+
<syntaxhighlight lang="csharp">public class MySingleton
 
{
 
{
 
private static MySingleton instance;
 
private static MySingleton instance;
Line 50: Line 50:
 
}</csharp>
 
}</csharp>
 
== Component-based example ==
 
== Component-based example ==
<csharp>using UnityEngine;
+
<syntaxhighlight lang="csharp">using UnityEngine;
  
 
public class MySingleton : MonoBehaviour
 
public class MySingleton : MonoBehaviour
Line 77: Line 77:
 
== Score tracking singleton ==
 
== Score tracking singleton ==
 
The singleton in this example keeps track of the game score. Getting and setting this value is done like so:
 
The singleton in this example keeps track of the game score. Getting and setting this value is done like so:
<csharp>MySingleton.Instance.Score += 5;
+
<syntaxhighlight lang="csharp">MySingleton.Instance.Score += 5;
 
Debug.Log ("Score is now: " + MySingleton.Instance.Score);</csharp>
 
Debug.Log ("Score is now: " + MySingleton.Instance.Score);</csharp>
  
 
And the singleton class:
 
And the singleton class:
<csharp>public class MySingleton
+
<syntaxhighlight lang="csharp">public class MySingleton
 
{
 
{
 
     private static MySingleton instance;
 
     private static MySingleton instance;
Line 130: Line 130:
 
== Time tracking and GameOver broadcasting singleton ==
 
== Time tracking and GameOver broadcasting singleton ==
 
This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:
 
This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:
<csharp>MySingleton.Instance.Register (gameObject);
+
<syntaxhighlight lang="csharp">MySingleton.Instance.Register (gameObject);
 
MySingleton.Instance.Unregister (gameObject);</csharp>
 
MySingleton.Instance.Unregister (gameObject);</csharp>
 
Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.
 
Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.
 
And the singleton class:
 
And the singleton class:
<csharp>using System.Collections;
+
<syntaxhighlight lang="csharp">using System.Collections;
 
using UnityEngine;
 
using UnityEngine;
  
Line 225: Line 225:
 
== Mapping static methods to singleton methods ==
 
== Mapping static methods to singleton methods ==
 
Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this:
 
Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this:
<csharp>MySingleton.Instance.Register (gameObject);
+
<syntaxhighlight lang="csharp">MySingleton.Instance.Register (gameObject);
 
MySingleton.Instance.Unregister (gameObject);</csharp>
 
MySingleton.Instance.Unregister (gameObject);</csharp>
 
should for simplicity be remapped to this:
 
should for simplicity be remapped to this:
<csharp>MySingleton.Register (gameObject);
+
<syntaxhighlight lang="csharp">MySingleton.Register (gameObject);
 
MySingleton.Unregister (gameObject);</csharp>
 
MySingleton.Unregister (gameObject);</csharp>
 
To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so:
 
To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so:
<csharp>using System.Collections;
+
<syntaxhighlight lang="csharp">using System.Collections;
 
using UnityEngine;
 
using UnityEngine;
  
Line 329: Line 329:
 
Singleton<Foo>.Instance will be Foo (your own class) and guaranteed to be a singleton. The concept was lifted from a MSDN article that I recently discovered.
 
Singleton<Foo>.Instance will be Foo (your own class) and guaranteed to be a singleton. The concept was lifted from a MSDN article that I recently discovered.
  
<csharp>
+
<syntaxhighlight lang="csharp">
 
         public sealed class Singleton<T> where T : class, new()
 
         public sealed class Singleton<T> where T : class, new()
 
         {
 
         {

Revision as of 20:44, 10 January 2012

By AngryAnt.

Description

People have recently asked about singleton creation quite often in the IRC channel so rather than retyping a basic implementation each time, I'll have this to link to. Yay! :)

Curious, but not quite sure what a singleton is? Ask a friend: [1]

Singletons are generally handy for providing easy access to game state and control code. I've provided example implementation for a basic class type which needn't be attached to a game object in order to function and after this an implementation which works as any other component.

Members of both singleton types are accessed the same way:

MySingleton.Instance.MySingletonMember;</csharp>
 
== The non-component example ==
<syntaxhighlight lang="csharp">public class MySingleton
{
	private static MySingleton instance;
 
	public MySingleton () 
	{
		if (instance != null)
		{
			Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
			return;
		}
 
		instance = this;
	}
 
	public static MySingleton Instance
	{
		get
		{
			if (instance == null)
			{
				new MySingleton ();
			}
 
			return instance;
		}
	}
}</csharp>
== Component-based example ==
<syntaxhighlight lang="csharp">using UnityEngine;
 
public class MySingleton : MonoBehaviour
{
	private static MySingleton instance;
 
	public static MySingleton Instance
	{
		get
		{
			if (instance == null)
			{
				instance = new GameObject ("MySingleton").AddComponent<MySingleton> ();
			}
 
			return instance;
		}
	}
 
	public void OnApplicationQuit ()
	{
		instance = null;
	}
}</csharp>
 
== Score tracking singleton ==
The singleton in this example keeps track of the game score. Getting and setting this value is done like so:
<syntaxhighlight lang="csharp">MySingleton.Instance.Score += 5;
Debug.Log ("Score is now: " + MySingleton.Instance.Score);</csharp>
 
And the singleton class:
<syntaxhighlight lang="csharp">public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
    }
 
    public static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int score;
 
 
 
	public int Score
	{
		get
		{
			return score;
		}
		set
		{
			score = value;
		}
	}
}</csharp>
 
== Time tracking and GameOver broadcasting singleton ==
This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:
<syntaxhighlight lang="csharp">MySingleton.Instance.Register (gameObject);
MySingleton.Instance.Unregister (gameObject);</csharp>
Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.
And the singleton class:
<syntaxhighlight lang="csharp">using System.Collections;
using UnityEngine;
 
 
 
public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
        Init ();
    }
 
    public static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int timer;
	private ArrayList listeners;
 
 
 
	private void Init ()
	{
		listeners = new ArrayList ();
	}
 
 
 
	public int Timer
	{
		get
		{
			return timer;
		}
		set
		{
			timer = value;
			if (timer <= 0)
			{
				foreach (GameObject listener in listeners)
				{
					listener.SendMessage ("GameOver");
				}
			}
		}
	}
 
 
 
	public GameObject RegisterListener (GameObject listener)
	{
		listeners.Add (listener);
 
		return listener;
	}
 
 
 
	public bool UnregisterListener (GameObject listener)
	{
		if (!listeners.Contains (listener))
		{
			return false;
		}
 
		listeners.Remove (listener);
	}
}</csharp>
 
== Mapping static methods to singleton methods ==
Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this:
<syntaxhighlight lang="csharp">MySingleton.Instance.Register (gameObject);
MySingleton.Instance.Unregister (gameObject);</csharp>
should for simplicity be remapped to this:
<syntaxhighlight lang="csharp">MySingleton.Register (gameObject);
MySingleton.Unregister (gameObject);</csharp>
To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so:
<syntaxhighlight lang="csharp">using System.Collections;
using UnityEngine;
 
 
 
public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
        Init ();
    }
 
    private static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int timer;
	private ArrayList listeners;
 
 
 
	private void Init ()
	{
		listeners = new ArrayList ();
	}
 
 
 
	public static int Timer
	{
		get
		{
			return Instance.timer;
		}
		set
		{
			Instance.timer = value;
			if (value <= 0)
			{
				foreach (GameObject listener in Instance.listeners)
				{
					listener.SendMessage ("GameOver");
				}
			}
		}
	}
 
 
 
	public static GameObject RegisterListener (GameObject listener)
	{
		Instance.listeners.Add (listener);
 
		return listener;
	}
 
 
 
	public static bool UnregisterListener (GameObject listener)
	{
		if (!Instance.listeners.Contains (listener))
		{
			return false;
		}
 
		Instance.listeners.Remove (listener);
	}
}</csharp>
Voilá! Less cruft in the world! Everyone rejoice!
 
== Generic Based Singleton ==
 
By [[Opless]]
 
This is uber simple, relies on the readonly keyword and generics to implement a threadsafe Singleton of practically any class.
 
Singleton<Foo>.Instance will be Foo (your own class) and guaranteed to be a singleton. The concept was lifted from a MSDN article that I recently discovered.
 
<syntaxhighlight lang="csharp">
        public sealed class Singleton<T> where T : class, new()
        {
                /// <summary>
                /// Singleton implementation, readonly and static ensure thread safeness.
                /// </summary>
                public static readonly T Instance = new T ();
        }
</csharp
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox