Why are some modules designed to have a singleton (most singletons are inherited from interfaces), and why are some others modules inherited from interfaces without having a singleton? I want to make a module but I don’t know which design to use.
If you’re not building an online subsystem and alikes, you probably want to build a module with the common accessor interface.
The Singleton (“Get()” module interface) makes sense since you aren’t allowed to run more than one instance of an engine module without breaking everything.
Aren’t modules supposed to have only one instance of them created and initialize once? Most modules initialize their singleton in StartupModule (the asset registry module does that) which is why I’m lost; should features and functions be put inside a Singleton or inside the module itself? In what situation each way should be used?
Modules are inherently singular, yes. You can actually find three different approaches in engine modules that have a public API.
Public API exposed through dedicated interface (IAssetRegistry, IContentBrowserSingleton, etc), which is itself acquired via the module interface.
API exposed as part of the module interface (eg. IMainFrameModule).
API exposed directly on module implementation (FPropertyEditorModule).
I’m pretty sure the only reason for this variation is differing levels of laziness. Number 1. is best as it gives the most encapsulation - 3 requires the implementation class to be public, 2 means users of the API also have access to IModuleInterface methods, which doesn’t make sense.
So yeah, go for 1 if you’re after clean code. Bear in mind though that this really only applies to modules that are intended to expose services and be loaded dynamically. If you plan to export classes from your module for direct use in other modules, then you’ll need to use static dependencies in which case you don’t really gain anything from this approach.