Name viable alternatives to the singleton pattern that are not dependency injection frameworks

From random bloggers to well known Unity Youtubers like Infallible Code and Jason Storey, everyone likes to hate on singletons these days but almost no one can name a proper, viable alternative in Unity. The typical suggestion is to first try out the Service Locator pattern, but that just seems like a singleton with extra steps. And now that too is considered an anti-pattern, just like singletons these days.

The last suggestions is always to use dependency injection frameworks like Zenject. But when I look at Zenject and Extenject I’m faced with hundreds of open issues, some of of which, while platform specific, are still critical to me as I’m targeting a wide variety of platforms.

And none of these frameworks have been recently updated, so I question the level of support that’s available to me. I need to deliver projects for clients on time. Depending on unreliable frameworks seems counter productive.

I’m also not making the next Pokemon GO or Raid Shadow Legends, two well-known games that supposedly use Zenject. These companies surely have resources dedicated to the framework’s upkeep internally. I don’t have that. Nor do I need to inject data for unit testing or in app purchase testing or whatever else they use it for.

I just want to find a scalable architecture model I can use for small to medium scope games of various genres. A solution that scales if necessary for things like global game state management, audio manager, a pooling system, a character manager for when there are an X amount of playable characters, etc. If not singletons, then what else is there in Unity?

1 Like

I’m not sure why you’re so focused on design patterns, they can be very useful in certain circumstances but also an awful distraction and even worse, obfuscation to code. They are also the source of many an argument online with everyone and their dog having an opinion.

The concept of a singleton has nothing whatsoever to do with dependency injection which itself is often based on a different pattern: inversion of control.

This class gives you the most basic and perhaps the most often used reusable singleton:

That said, I am absolutely not going to go deeper into the design pattern if it’s a debate that’s wanted due to what I said above. :slight_smile:

1 Like

Two reasons. I keep getting bombarded with “singleton bad” message everywhere I go. And I have a new gig to rewrite a project which has too many tightly coupled scene scope singletons, so I was wondering what else is out there, design pattern wise (besides doing singletons the correct way).

That’s fair enough but alone those statements are meaningless. I too could state a few but there’s a reason and circumstance where they are bad. In themselves, they’re not bad so surely it has to be one of, they are bad only if you’re using them in that bad context.

They have their use but like anything in this world, always in moderation and when appropriate.

Maybe it’s appropriate in your circumstance. Sorry if I’m sounding too general; I just resist statements that X is bad and Y is not.

2 Likes

I ve been in this rabbithole when started learning about design patterns, everywhere people call singleton a bad pattern without providing a replacement. Which is frustrating but as you ll figure out there are no exact replacements for any of the patterns.
The whole point of those statements is that your architecture ,that needs singletons to function, is to be changed and not just replacing a pattern inside of it that does exactly the same thing.

In the end singleton is a very powerful pattern which can be leveraged in the context of Unity. Where for example static classes can not replace it cause they can’t get serialized.

Personally when need to have multiple scenes opt out for a static service provider, exposing interfaces rather implementations. But thats not a solutions for all scenarios. It all boils down on the context and specific needs of your current project.

1 Like

I am curious as of why you phrased the thread title “name VIABLE alternatives”. That implies to me that you are having a list of unviable alternatives in mind. There are lots of methods of decoupling code. Maybe you can share which ones you deem unviable and which ones you like and why.

From the top of my head here are two which don’t use any framework:
a) Use ScriptableObjects as factories to provide your dependencies. You can wire those up in the inspector.
b) Hand down any dependency with every method call. No global access. This will lead to loooong parameter lists, but it is a solution. All dependencies are fully defined by the parameter lists.

Whether or not those are viable in your opinion I can not know. I have seen both used in real projects though.

Because everyone and their mom say “singleton bad, don’t use it” but can’t provide any “viable” alternatives that are not DI. Viable meaning what’s generally considered a good practice these days.

That said, most of these bloggers and Youtubers seem to come from enterprise where the product has to live for decades, has to be as extensible as possible and has to be able to swap out complete solutions for totally different technologies.

In which case DI is applicable, but in Unity where I have like 6 months for a project rewrite and then perhaps 6 months of post launch support and updates, DI’s an overkill. Not to mention not natively supported in Unity in the way Zenject & co do it.

So if singleton bad and DI is an overkill, what else is there?

I use SOs for immutable data, then load them up in a Monobehaviour if runtime data has to change. I see them as complimentary and mainly as designer tool. Odin serialized dictionaries in SOs are a treat.

Functional programming in Unity seems like an overkill.

Since you’re listening to those people when it comes the architecture of your game, you will need to ask them.

I strongly disagree with that opinion. Singleton has its purpose. Period. People use it when they shouldn’t? It is not the screwdriver’s fault that people sometimes use it as a makeshift hammer.

Also people often mix up singleton with static/global access, they aren’t the same. Although in Unity singleton usually goes hand in hand with global access for some reason. Anyway, you really should ask those people.

I consider this “swap out with something totally different” a myth. Has anyone ever done that without a significant rewrite? I’d be genuinely interested in examples. Yes, you can swap out something that implements the same API but even if API compatible, concrete implementation reliance always bleeds through to some extent. Database Repos are a nice example for this. Yes, you can swap them out with completely different tech but even if the api is compatible, suddenly all your performance assumptions can be thrown out the window. So I’d agree on that part.

I’d disagree in the longevity of projects. Especially service or f2p games can run for decades too.

Ah nice, you picked up where I was going with this :smile:. Yes, I agree, though it could be worth it for logic heavy parts. It was just one solution that came to my mind. Maintaining these lists is a chore but it can pay dividends as the dependencies are crystal clear. Combine it with immutable data structures and it becomes really impractical but very nice (in theory).

With SOs I meant to use them as a global access tool instead of a “singleton” replacement. You can achieve the same with them (global access, swap out possibility, implementation abstraction). Very handy if you make one proxy SO which just references the actual SO data. You can drag in the proxy SO to your scripts and then swap out the real implementation/data for all scripts easily since they all reference the same proxy.

1 Like

I mean, a lot of singletons I’ve seen should really be static classes. For a couple of versions now, you can use the player loop interface to create custom systems that run their own update loops. Combine that with loading data into static variables, and you can get a lot of stuff done that used to be best done by a singleton.

But other than that, yeah, they’re fine. Dependency injection is a great technique, dependency injection frameworks are generally insanity on steroids.

Although as anything else, the right tool varies. Statements on the form “pattern X is bad” or “pattern X is good” without any context about what it’s good or bad for is generally just a sign that somebody’s either just learned something new in College that they think is the shit, or that somebody’s looking for a fight.

Do you have any systems that you’re using singletons for that you’re wondering what you should do instead with, or do you just want to argue about what somebody on youtube said?

2 Likes

Sounds like something the Open Project is/was doing from what I’ve heard. I’ll look into it, thanks.

The job I’m hired for is to rewrite a card/VN-hybrid game that’s largely driven by Bolt (UnityVS) graphs which hard reference several singletons such as BoardManager (processes played card data), PlayerHandManager (processes cards in hand/s), DeckManager (deals with decks and discard, shuffling, etc), SetupManager (which holds a bunch of dictionaries of assets mostly), CharacterManager (handles VN story progression for characters), AudioManager, TaskManager (for round goals, a sort of mini quest system), AnimationManager… there are a couple more.

And the singletons themselves often hard reference each other and are bloated, since most of them hold both the data and the logic that iterates on that data AND data of other singletons. All of that goes out the window instantly, including Bolt. So I’m not using singletons for anything yet. There likely will be one for a new AudioManager and perhaps one for a card pooling system. No other commitments so far.

The game is largely UI event driven, so a custom player loop is likely not as relevant. Nothing runs in Update(), at least not for user made code. The VN part is handled nicely by Naninovel asset so I don’t have to worry about that much. And just about the only thing I’m keeping are the card SO assets which work well enough for the purpose. Everything else is getting redesigned/rewritten.

Which is why I’m posting on the forums because singletons in this project are abused and because I’ve similarly sinned in some of my own past projects and also because of the general “singleton bad” sentiment. ie I’m looking to expand my knowledge that can be practically applied to my future projects. Perhaps not necessarily this one, but if “singleton bad” then what’s better? All you get on the internet as an answer is DI frameworks. I don’t like that answer. Hence the post.

Right.

It for sure sounds like most of those things should just be things. So you’d have a PlayerHand and a Board and a Deck and whatnot, but those would not be singletons, just things that are created as necessary. That makes it a ton easier to tear down and set up a new game.

In order to have them not be singletons, I’d have a game setup script that knows how to create those and binds up any necessary assignments between them.

Some systems are nice to have as globally accessible things - like whatever’s responsible for playing music. That’s because that system needs to persist between different parts of the game - for the music system’s case, in order to fade between the game music and the menu music. You can have that as different instances of music management that all need to both fade out and fade in independently, but that sounds (hah) like it’d be a lot harder to manage.

Player progress is interesting, because it has to be fetched from and written to a save file. There should only really be a single instance. Then again, for testing purposes, it’s very nice to be able to start a level with a differently setup progression without having to visit the save system. So I think that too is just a blob of data that you pass to the game.

The whole “just make them and assign references as needed” is exactly how you’d write a game in 1990, and it still works today. Just start at the top and make all the things you need, and give stuff references to the things they need. You don’t really need patterns, you just need to write the code that matches what needs you have. Patterns are nice to know about so you have known solution shapes to known problems, but frameworks are very often overly complex.

1 Like