Singleton design.

Hi all!

I know this question may be quite opinion based. Basically I am considering two options for global access scripts design.

  1. Make a singleton for every single instance manager object (e.g. in a single player rpg game - one singleton object for databases, one for inventory, one for UI, one for dialogues, etc.).
  2. Make one singleton object (let’s call it GameManager) that would hold a reference to all other managers.

Is any of these options better than the other one? I’m aware that there is probably no significant difference, except for e.g. code readability. I’m asking this because I sometimes see people wondering “Am I using singletons too much?”, “Is it bad?” etc.

Good question.

First, I’ll just state my answer: Option 2 or a derivative of it.

Why?

While Unity(and game programming in general) encourages or even forces you to use practices that would be considered “bad” on the other side of the programming fence, it’s still important that we try to hold good standards. Normally, we should suggest that a singleton not be used at all in this case:

  1. Their global nature can hide the dependencies within your codebase. Making an object global to avoid explicitly passing it along is considered a “code smell” in the application world.
  2. Singletons violate the Single Responsibility Principle.
  3. They encourage tight coupling among your codebase.
  4. They are difficult to mock for Unit Testing(which is already hard enough in game programming).
  5. They are inherently a product of lazy loading.

Lazy loading is bad because it puts off the decision to load the resource to another time. In this example, the decision to load the resource is made whenever you first use the resource and this decision can be made unknowingly to the programmer. This is the big problem with lazy loading. The initialization time of the resource can change quite frequently without the programmer even realizing it or considering the implications.

For this reason, an explicit initialization order is preferred. Of course, this could be done with the Singleton pattern by explicitly asking for a reference in some startup order, but in such case we would essentially be back to a convoluted option two.

While option two does not solve problem one or two(which are arguably the most important), it is definitely the better of the two.

While we would love to avoid those problems by using better coding patterns, in game development and especially in Unity it can be quite difficult to uphold those standards. Ideally, we would try to use no globals at all, but alas we are in no perfect world. Game programming often prefers and at times forces that we break practice. Therefore, I think option two is your best solution.