I make sure when designing software/firmware to make heavy use of dependency injection so that different pieces of the application are not directly coupled to one another. This also allows me to (potentially) unit test each piece of code using mock dependencies.
However, the dependencies that need to be passed into constructors need to be created somewhere. In other words, the application has to start from nothing at a single point (i.e., main).
I am wondering, is it good practice to represent the application as a whole as a singleton?
class IApplication
{
public:
virtual int run(int argc, char* argv[]) = 0;
};
class Application
{
public:
static IApplication& instance();
};
To be used like so:
int main(int argc, char* argv[])
{
return Application::instance().run(argc, argv);
}
The implementation of the Application
class then is in charge of constructing all the root dependencies and those objects which depend on them.
If this is not a good way to start an application, please explain why and provide a better alternative.
Based upon the very helpful answers so far, I thought it would be useful to add some more context. I develop firmware for embedded systems. I can write my application code so that it is abstracted (e.g., via dependency injection and abstract interfaces) from the hardware (i.e., register and memory-mapped addresses). However, at some point, I need to directly access those peripherals to get the abstract drivers to be injected. Those peripherals are at specific addresses in memory that are accessed globally (i.e., they are "singletons"). I would probably write Application
to access these global hardware "objects" directly. However, if I do that, creating 2 instances of Application
would be incorrect (they both directly access the same hardware), thus I was thinking, Application
should only have a single instance and thus be a singleton.
I could get extremely abstract like so:
Platform myPlatform(Processor::instance());
Appplication myApplication(platform);
Where the application runs on any "Platform" (probably an interface) and the Platform
runs on a specific processor/hardware of which there is a single instance (i.e., the one executing the code); but this will get a bit inefficient.