Avoiding Singletons in Unity

Before starting, I must say that this is the first part of avoiding Singletons in an effective way. The second part is about Dependency Injection, but before reading that I suggest to finish reading this post.

Our target should always be creating a clean, maintainable code regardless of you working alone or with a team. I can’t imagine a proper Unity game having a small code base in these days. Well, if you provide everything from libraries, then the story may be different. However, being a bit tidy won’t bring any harm, right?

You kiddin’! We know Singletons are bad..

If you are here, it is possible that you know the story. Singletons are global to rest of your code base. Every class is accessing to it directly, and they depend on concrete implementation. We don’t know when they are called,  and their state. They are not testable in a good way, and violating most of the SOLID principles etc. Problems are very well known. So avoiding singletons should be important!

Even though big frameworks and libraries are still using it for the convenience, we should avoid using it and favor some other approach for the sake of clarity and maintainability. 

Here is the Singleton approach for the MonoBehaviors;

public class Singleton : MonoBehavior 
{ 
    private static Singleton _instance;

    public static Singleton Instance 
    { 
        get { return _instance; } 
    } 

    private void Awake() 
    { 
        if (_instance != null && _instance != this) 
        { 
            Destroy(this.gameObject);
            return;
        }

        _instance = this;
        DontDestroyOnLoad(this.gameObject);
    } 
}

And here is another one for the non-MonoBehaviors;

public class Singleton<Type> where Type : class, new()
{
    private Singleton() { }

    private static readonly Lazy<Type> _instance =
        new Lazy<Type>(() => new Type());

    public static Type Instance { get { return _instance.Value; } }
}

Idea is the same for both of the approaches. Classes carry their only one instance. This instance is going to live during the entire lifespan of the application. We will be able to reach it, since the instance is static. 

Give me an alternative?

I agree that Singletons have couple of legitimate usage, but as game developers, we sometimes like to abuse the usage of some design patterns.

It is just easy to access to the ScoreHandler from anywhere in the game. Yes! So what? Games are a bit different than regular software products, and having a global state is not something weird at all. Maybe!.. But there should be a better way instead of spamming all managers and handlers everywhere.

Creating well-defined relationships between classes would naturally decrease the need of having a Singleton. Your design must be coherent as much as possible but we all know that. Regardless of that it still can get messy when the code base is getting bigger.

READ  Observable values: Stop Checking a Value on Update

Having a Singleton Game Manager?

Imagine that you have a GameManager class which contains all the possible services in it and it is a Singleton facade. So all classes that need those services will depend on GameManager. In addition to that GameManager will pick the right handler for the job. Surely, it fixes some of the problems that are introduced before, however it introduces new problems.

  • We depend on the concrete implementations not abstractions.
  • GameManager will be way far from having Single Responsibility.
  • It is still possible that this might be abused by the classes in the lower level. So we may also violate the Dependency Inversion principle.
  • We can’t claim GameManager is testable as well.

What is it then?

Service Locator Pattern

Avoiding singletons is not so hard. However, what we are using instead of it shouldn’t introduce more problems than we already have. So? The next improvement step would be introducing Service Locator Pattern. This is also a bit controversial and some claims that it is an anti pattern. As long as you don’t abuse the pattern, I think it is quite acceptable. 

If you would like to go with this way, you just need to implement this once. Then you can use it in all of your games. I guess I can’t make a better definition than Wikipedia does;

The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the “service locator” which on request returns the information necessary to perform a certain task.

Wikipedia

Service Locator Pattern as a solution for avoiding singletons
Service Locator Pattern

So simply, we create a static class containing a Dictionary which maps interfaces to service instances. When needed, we just use it to locate the instance and do the operation we need from the service. Here is a simple implementation of ServiceLocator;

public static class ServiceLocator
{
    private static readonly Dictionary<Type, object>
        Services = new Dictionary<Type, object>();

    public static void Register<T>(object serviceInstance)
    {
        Services[typeof(T)] = serviceInstance;
    }

    public static T Resolve<T>()
    {
        return (T)Services[typeof(T)];
    }

    public static void Reset()
    {
        Services.Clear();
    }
}

Of course this example can be improved, but this is the simplest implementation I can think of.

Advantages of Avoiding Singletons with Service Locators

At one glance, we can actually see what we have gained;

  • We can register instances using the interfaces as type parameter. So we don’t have to depend on the concrete implementations.
  • We can reset the locator anytime we want. So we also gained some control of the service lifespan.
  • We can use it for unit testing and include or mock any services we want to use in that specific test.
READ  How to Make a Modular UI in Unity

Let’s write more code and use it.

// 1. Service Interface
public interface IScoreHandler
{
    int CalculateScore(Hit hit);
}

// 2. Service Implementation
public class EasyScoreHandler : IScoreHandler
{
    public int CalculateScore(Hit hit)
    {
        return 10 * hit.area;
    }
}

// 3. Service Registration
public class ServiceBinder : MonoBehaviour
{
    void Awake()
    {
        ServiceLocator
            .Register<IScoreHandler>(new EasyScoreHandler());
    }
}

// 4. Service Locating and using
public class Scoreboard
{
    private int score;

    public void IncreaseScore(Hit hit)
    {
        score += ServiceLocator.Resolve<IScoreHandler>()
            .CalculateScore(hit);
    }
}

I have tried to keep everything as simple as possible and I hope it makes the point. So, avoiding singletons is possible with the Service Locator pattern. Oh, you can say that this is an indirect Singleton. However, it is not like that. This pattern gives us great flexibility such as;

  • In case of a change on a service requirement, we can create another implementation. Then, register it in the ServiceBinder. We don’t have to change anything else. This might be a really good usage for performing A/B testing as well.
  • Unlike Singleton usage, change impact is quite controlled. Service Locator usage won’t require any big modification unless we change the interface.

It is possible to improve the ServiceLocator introducing some kind of scope or context. However, my purpose here is just giving the basic idea. You can have different variations as well.

Conclusion

I honestly never seen anything not controversial related to this topic. In an ideal world, we wouldn’t need Singletons but world is not that ideal. Even though, Service Locator helps us on avoiding singletons, it has some negative sides, too.

Service Locators are hiding the complexity. This side affect can be a huge disadvantage if you are designing an API. You’d give horrible times to users of the API due to lack of explicitness. However, you can favor this pattern in Unity instead of using lot’s of Singleton. 

As a final side note, if you have arrived here, understood the Service Locator Pattern and it did feel reasonable, you should definitely invest some time to learn Dependency Injection (DI). It wouldn’t be wrong to say that Service Locator is the simplest form of a DI container. There are many DI frameworks out there. Some has a lot of good features such as injecting with parameters, ids, and conditions. So you can have full control on your dependencies. If you feel interested, you can read my post on Dependency Injection in Unity. 

Please write comments, criticize it. I would love to make my content more quality with your feedback.

13 Responses

  1. Sebastian says:

    Interesting take on this problem. I have been struggling with not using Singletons in my Unity projects for quite some time now. I also used the Zenject Framework for some of my projects but found it to be quite complex and high level. The basic service locator pattern seems to be a better choice. Even though I don’t like the service locator to be static I guess there is no other choice in Unity to that. 😀

    • erdiizgi says:

      I really get what you mean about Zenject. Whenever I start a new project, I don’t start with Zenject but within the first refactoring period I am trying to adapt my project to it. You are also right about complexity 🙁

      Having the service locator as static sounds a bit bad, but also libraries like Zenject do the same. Since they hide it, we don’t realize. So, you can do the same.

      For example, you can have a ServiceMonoBehavior which has a protected method called getService. Or if you wish this for all the mono behaviors, you can use an extension method – https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods – . This should look better and you would hide the ServiceLocator for unity mono behavior entities.

  2. Woody Payne says:

    I’m currently working on a configurable and persistent scene manager for my project and a singleton seems like the logical conclusion. Within the context of a game project, singletons aren’t that big a deal to me, but coming from a web development background I’m well aware how much of a nuisance they could end up being as this project grows, so this morning I’ve been reading articles on the subject. There’s so many “SINGLETONS BAD” ones out there but very few offer alternatives, which makes it a bit frustrating trying to avoid them.

    I hadn’t heard of a service locator before now and yet I believe it’s exactly what I’m looking for. Thank you for this article!

    • erdiizgi says:

      Hi Woody, thank you so much for you great comment. If I could try to explain why I wrote this post, I wouldn’t be able to summarize it better. I am glad that it gave you some positive perspective 🙂

  3. Hi. I made a new game object that I called ServiceBinder (in lack of better words) but what is recommended approach to trigger the ServiceBinder class Awake method? Place in the camera in the scene? I have heard that many use the camera for placing all sorts of things in the scene that should just work and be there.

    • erdiizgi says:

      Hi, I guess ServiceBinder is a fine name and it also kind of shows that you’re coming from enterprise software development world 🙂

      If you would like to use game object’s MonoBehavior for this purpose, you should mind the Script Execution time! You don’t want to end up with any null references. As far as remember, the gameobject order in ‘Hierarchy’ doesn’t have an impact on Script Execution Order. I also don’t like the manual manipulation of it ( https://docs.unity3d.com/2019.3/Documentation/Manual/class-MonoManager.html )

      So I would use ServiceBinder’s Awake method for binding, and I wouldn’t use any service in another MonoBehavior’s Awake method. If you need to locate a service in a MonoBehavior, just use the Start method for it.

      After all, Awake should be used for setting up a component.
      Start should be used for setting up things that depend on other components.

      Please do ask more in case there is something unclear.

  4. Kamalen says:

    Please note that you haven’t actually removed Singletons here. Singletons are classes that exists only once and only this. You have only changed the way it’s accessed.

    • SMWYG says:

      “Singleton” doesn’t merely mean a class that has one and only one instance.

      No, a service locator is very distinct from a Singleton in several important ways. The Singleton as described in the classic Gang of 4 book, and as implemented traditionally overloads onto the Singleton class both its normal functions as well as controlling instantiation and access to that class. This then impedes the ability to swap implementations later, which can make the code less testable and less portable.

      There is nothing wrong with the concept of a specific object of which only one should exist, nor is there anything wrong with the concept of creating a way to make it widely available across a project. Where “Singleton” as described in Gang of 4 and as described above runs into problems is how tightly it winds its way into a codebase and how difficult it is to isolate, test, and extract if required.

    • uuTuTu says:

      Unlike Singleton you can use interfaces for the Service Locator approach here, which abides the Dependency Inversion principle better than the conventional Singleton pattern.

  5. Rasmus says:

    Very clear explanation and clean examples! Thank you!

  6. Tom Devaney says:

    Great post. Clear and concise examples. At first was skeptical, but I definitely see the advantages over the singleton pattern, although they’re very similar.

  7. Zachary M says:

    I previously used a main GameManager singleton that would somewhat act as a service locator, with objects calling the Instance to access other Manager classes. But this object also was quite bloated in its functionality as it tried to encompass everything. I think this fits well into my programming style.

  1. 7th December 2018

    […] the previous post, I have exposed the problems regarding the Singletons and arguably proposed the Service Locator […]

Leave a Reply

Your email address will not be published.

Avoiding Singletons in Unity

time to read: 5 min
13