Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Why are singletons so popular with Unity devs?

Discussion in 'Scripting' started by deltron1830, Mar 9, 2015.

  1. deltron1830

    deltron1830

    Joined:
    Mar 20, 2013
    Posts:
    27
    SIngletons seem to be recommended a lot in various Unity tutorials and whatnot. example

    http://www.indiedb.com/groups/unity-devs/tutorials/delegates-events-and-singletons-with-unity3d-c

    Code (csharp):
    1.  
    2. // This class sits on my camera and handles all the clicks I send with a Raycast
    3. public class Clicker : MonoBehaviour
    4. {
    5.   // Singleton
    6.   private  static Clicker instance;
    7.  
    8.   // Construct
    9.   private Clicker() {}
    10.  
    11.   //  Instance
    12.   public static Clicker Instance
    13.   {
    14.   get
    15.   {
    16.   if (instance ==  null)
    17.   instance = GameObject.FindObjectOfType(typeof(Clicker)) as  Clicker;
    18.   return instance;
    19.   }
    20.  
    21.   // Do something here, make sure this  is public so we can access it through our Instance.
    22.   public void  DoSomething() { }
    23.  
    They seems to have a bad rap with the stack overflow crowd.
    http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons


    Personally I dont like them. Heres my take

    Pros
    * Being able to do this, "Clicker.Instance.DoSomething();" without a reference is handy
    (Though you can get that anyway with a regular old static class, if it doesnt have to be a monobehaviour)

    Cons
    * Too complicated for what it does
    * You dont know when this code will be run.. " GameObject.FindObjectOfType" I dont want a find to run during the game, Id rather run them all at awake() and start() when I dont care about any performance hit
    * Needs to be implemented for every component

    I sorta feel like a heretic though since they seem to be so commonly recommended. Even Pushy Pixels recommends them.
    What I tend to do for all my game management stuff is have a gameobject with all my game management components on it. Then I either make it a prefab or have it not be destroyed on load another scene, depending on whether I want it to persist from scene to scene or not.
    Stuff gets references to my game manager component at start() or awake() or in the case of things being instantiated is passed to them by their spawner after they are instantiated when they are being setup.

    ...
     
    Last edited: Mar 9, 2015
  2. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    Please update using code tags? :)
     
  3. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    IMO, there are some inconsistencies by mixing singleton and component pattern that Unity uses in MonoBehaviours.

    Sometimes I find useful to use something like:
    Code (csharp):
    1.  
    2. static public Behaviour Instance;
    3.  
    4. void Awake()
    5. {
    6.   Instance = this;
    7. }
    8.  
    But write no code to ensure a single instance (as there are many problems with objects living across scenes and so on).

    There are cases in that it's much much better to create a static class (non-monobevaviour). Even better, in C# static constructors are called only when the class is used for the first time in code.
     
  4. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    old argument all over the internet , I dont care what people use if it works for them, its not difficult to understand either if you come across it in another persons code. There are other pro/con arguments as well but anyway .. I find I dont need them. I dont need to make a entire class static either .. I find making a method or field static is enough to get the same behaviour needed and does not care if you have more than one instance of the class either eg :

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class EventManager : ScriptableObject {
    6.  
    7.        
    8.     //-----------------------------------------------------------------------------------
    9.    
    10.     public  delegate void GameEventHandler(EventForGame eventToDispatch);
    11.    
    12.     public static event GameEventHandler gameEvent;
    13.    
    14.     public static void dispatchGameEvent(EventForGame eventToDispatch){
    15.  
    16.        
    17.         if(gameEvent != null){
    18.             gameEvent(eventToDispatch);
    19.         };
    20.     }
    21.    
    22.     //-----------------------------------------------------------------------------------
    23. }
    24.  
     
  5. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    I do use find as well during awake cycle to cache things dynamically , other times I hard code the reference in the inspector. Coding purists will swear at me for this but hey .. its there and it works ;) The day I find it lets me down I will just change it no problem.
     
    jtsmith1287 likes this.
  6. DanSuperGP

    DanSuperGP

    Joined:
    Apr 7, 2013
    Posts:
    408
    Because many Unity devs don't have a CS background, have never heard of dependency injection, nor do they write unit tests.

    That is also a very messy way to create a singleton since as it will do a GameObject.find on first call, which could be at any time and will still return null if it doesn't exist. It's better to just do this.

    Code (CSharp):
    1.  
    2.  
    3. public class Clicker : MonoBehaviour
    4. {
    5.     private static Clicker _instance;
    6.     public static Clicker instance
    7.     {
    8.         get  { return _instance; }
    9.     }
    10.  
    11.     void Awake()
    12.     {
    13.          if(_instance == null)
    14.          {
    15.                _instance == this;
    16.          }
    17.          if(_instance != this)
    18.          {
    19.                DeleteImmediately(gameObject);
    20.          }
    21.     }
    22.  
    23. }
    24.  
    25.  
    It still doesn't have lazy instantiation, but at least it doesn't do a random find and actually guarantees only one in your scene
     
    jtsmith1287 and Kiwasi like this.
  7. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
    this is the approach i take
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    4. {
    5.     protected static T instance;
    6.  
    7.     public static T Instance
    8.     {
    9.         get
    10.         {
    11.             if (instance == null)
    12.             {
    13.                 instance = (T)FindObjectOfType<T>();
    14.                 if (instance == null)
    15.                 {
    16.                     Debug.LogError("An instance of " + typeof(T) +
    17.                         " is needed in the scene, but there is none.");
    18.                 }
    19.             }
    20.             return instance;
    21.         }
    22.     }
    23. }
    24.  
    Than i implemeant it like
    Code (CSharp):
    1. public class GestureManager : Singleton<GestureManager>
    This cuts down on haveing to add the singalton stuff to every manager class i got, which i ussualy got atleast 2 per game
     
    jtsmith1287 likes this.
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    OK, here's the thing...

    There's 2 options you describe there.

    The first is a design that assumes only one of the managers will exist. There's no way to guarantee only one exists... it just assumes only one exists. So when you get the reference to it on 'start' or 'awake', who is to say more than 1 exists or not and if this script grabbed a reference to the correct one or not.

    The second option where it gets handed a reference actually can work, because whatever controls handing that reference over can guarantee which one is handed over.

    The Singleton pattern is for the first half of your design. It ensures that only one exists, so that when you go to retrieve a reference to it... you are guaranteed to get that one.
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Singletons are popular in Unity for a number of reasons. It's a design pattern with obvious benefits. If fits well within the Unity framework, many other design patterns end up fighting the Unity way. It works well with DontDestroyOnLoad. It's easy to understand.

    I do agree that the OP code is perhaps one of the worst implementations I've seen. I have my doubts it would even compile within Unity, pretty sure touching the constructors of a MonoBehaviour is a no go area.

    For unity devs the question of "how do I make a globally accessible class that will be persistent throughout the game?" comes up quite frequently. The easiest answer to reach for is the singleton.
     
  10. Deleted User

    Deleted User

    Guest

    They're popular because you can drag & drop them onto GameObjects and you can edit their fields and Unity will serialize them. Unity can't do that with regular static classes.
     
    MortePCAndVR, Kiwasi and spryx like this.
  11. spryx

    spryx

    Joined:
    Jul 23, 2013
    Posts:
    556
    this!

    Much easier to keep track of.
     
    DanSuperGP likes this.