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  Hello World! (Not WordPress' auto post)

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  Observable values: Stop Checking a Value on Update

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.