I am pursuing object oriented design. So we don’t want to use globals but yet sometime we have a module that most other modules use. This means we have to just pass it to all other modules and this can be literally all modules!
class Logger
{
public:
Logger(void);
~Logger(void);
};
class Calculator
{
public:
Calculator(Logger *logger);
~Calculator(void);
};
class Taxation
{
public:
Taxation(Logger *logger);
~Taxation(void);
};
So the idea is that the Calculator
and Taxation
modules use the Logger
module to log everything. Similarly most other modules will use it too, and logging is required everywhere. Is this method okay or should Logger
be global instead?
0
Avoiding global variables (and singletons, that are global variables in disguise) is a good thing to strive for. The most important is not to think about it as global and singletons being impure OO, that doesn’t get you anywhere. The important concept to keep in mind is ‘dependencies’. Any dependency that is explicitly injected into the client is loosely coupled. Any dependency that is invisible from the outside of the client is tightly coupled.
Yes, it takes more code to explicitly inject dependencies, but your code ends up being more flexible, more testable and also easier to reason about.
In C++, if you can, inject your dependencies as template parameters. If that isn’t an option, consider using std::function. Passing by raw pointer isn’t a good idea, but you could consider using a const reference.
B.t.w, a while ago resulting from a linkedin discussion I created a logging library (that later others contributed to) excactly for the reason that in logging libraries the singleton pattern is grocely overused. There is no need to use singletons (or global variables) for things like a logging library.
http://pibara.github.io/libKISSlog/
In other situations, singletons are often used in resource management scenario’s. This blog post on an alternative to global variables and singletons for scarce-resource allocation, may be useful:
It would be better if you define the Logger as a Singleton instead of passing the object on each class.
Define the Logger like:
class Logger
{
private:
Logger()
{
//private constructor
}
public:
static Logger& sharedInstance()
{
static Logger singleTon;
return singleTon;
}
~Logger()
{
// Cleanup
}
};
Wherever you need logger, get it like:
Logger::sharedInstance();
8