frob said:
The Singleton pattern generally has a private constructor and is explicitly not virtual nor derived from a base with virtual methods, so it can't be subclasssed nor instantiated.
Jikoob said:
Default unity singleton implementation handles its own creation which may be troublesome when you deal with access via interface.
To answer both these points - subclassing of singleton is given as a specific example in “Design Patterns” by GoF - a Singleton as an abstract base class, which selects a specific subclass when instantiating. From my experience, it's sometimes used when you have platform-specific functionality, for example, “StoreManager” singleton which actually will be “AndroidStoreManager” or “SteamStoreManager”.
Jikoob said:
For example I can't imagine how AchievementsManager could not be hidden behind interface since achievements API calls are different on all platforms.
Agreed, I think it's one of the simplest approaches. I just kinda refrain from creating interfaces for eg “GameManager” that will specifically have just one implementing class - but I can see the appeal in that, I kinda like how C++ separates class definition vs implementation, so I can view source of definition and don't care about implementation details. And yeah, I agree that you can view it as a consistent approach.
For example, if an Enemy needs a reference to IAudioManager, then:
Engine.CreateManager IAudioManager → Engine.CreateManager IEnemyManager(IAudioManager) → IEnemyManager.SpawnEnemy(IAudioManager) → Enemy.Initialize(IAudioManager)
Yeah, this approach would be an example of a dependency injection. Though as you mentioned it creates a bit of a boilerplate, and I guess it's one of the things that DI injection frameworks want to fix.
And I guess I share the sentiment about DI frameworks, not sure if I like them - personally, Singletons with their implicit dependencies were good enough for me, so I didn't have a reason to use DI injection. Maybe if I would need to write more unit tests, I would change my opinion.