Lets say I use Dependency Injection and don't use a DI framework. So the injection is direct rather automatic. How I should handle the logger class? All the objects, (thousands) should have a Logger reference in their constructors? (We don't consider Singletons and Service Locater as they hide the dependency, and are pathological liars.)
How I should handle the logger class?
You should instantiate it and inject it into stuff that needs it.
All the objects, (thousands) should have a Logger reference in their constructors?
So what? If those objects need to log, then they need to get that dependency somewhere.
I would argue that have such pervasive dependencies is a smell, even for logging.
You basically have two options.
Use the composition relationship
You would't pass a class implementing a
Log interface to a class, but you would create an
abstract class where, in its constructor, you directly initialize it's
protected Log member with
new instance of your class implementing the
All classed which need to use the logger will then inherit this class and if you at any time in the future need to change the procedure of loggin mechanism, you can just swap out the one
new in your
base abstract class to a new logger and the change will be propagated throughout all your classes.
Use static methods
Logging is such a simple task, it produces no side effects. It merely opens a stream to log (be it a database or a file) and flushes the log contents there.
Because of its simplicity, logger can go into the utilities package.
However, there is one problem. If you, at any time in the future, decide, you want to change the way processes are logged, you will have to alter the logger class and its logging methods. In this process you are either very likely to lose the initial logging mechanism or going to comment out code for the initial procedures, which will make your code messy.
Where I work, we use the first approach - a simple logging interface, containing methods like
logError and have classes implement the interface.
Even though we usually restrain from the composition relationship, because it is hard to mock, the logger class, as I have said, is so simple, we have made an exception for it, because we still like it a tad more than having a static logger.