Before starting, I must say that this is the first part of  how to effectively avoid Singletons. There will be another post, and when it is finished you will find a link at the end of this post.

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

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. Everyone 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, and violating most of the SOLID principles etc. Problems are very well known.

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

Here this is the Singleton approach I have been using 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, so the instance is going to live during the entire lifespan of the application. We will be able to reach is using the class 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. So what? Games are a bit different than regular software products, and having a global state is not something weird at all. I agree, 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, it still can get messy when the code base is getting bigger.

Having a Singleton Game Manager?

Imagine that you have a GameManager class that contains all the possible services in it and it is Singleton facade. So all classes that need those services will depend on GameManager and game manager will pick the right handler for the job. Surely, it fixes some of the problems that are introduced before, but 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

The next step improvement 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 and 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

So simply, we create a static class containing a Dictionary which maps interfaces to service instances. When needed we just use 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. 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.

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 but I hope it makes the point. 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 we want to change the service implementation, we can create another implementation and register is 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/context. However, my purpose here is giving the basic idea of it. 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. Therefore we need to have some accessibility. Even though, Service Locator does this in an maintainable way, it has some negative sides, too.

Service Locators are hiding the complexity and this is a huge disadvantage if you are designing an API. You can give horrible times to users of the API due to lack of explicitness. However, for game programming with Unity, you can favor this pattern instead of using lot’s of Singleton. 

As a final side note, if you have arrived here, understand the Service Locator Pattern and it does 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 and they have a lot of good features such as injecting with parameters, ids and conditions. So you can have full control on your dependencies but this is a topic for a new post. 

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