I made no critisism of Log4Perl. My expressed opinion was limited soley to the "singleton pattern".
The OP gave reference
Anywhere I need to log something, I call get_logger() and then call my methods, typically without a temporary variable in the style of Log::Log4perl->get_logger("logger_name")->log("message").
In that, he is hard coding two invarients all over his codebase: "Log::Log4perl" & "logger_name". By doing so, he is creating a maintainance problem.
One solution is to confine those invarients to a single place by making the call once at the top level of his application and sharing the log object returned with the deeper levels of code via a global. Another is to hide the invarients behind a package global in the form of a function name. Both perfectly practical, sensible solutions.
The thing I noted is that either of these will work just as well with a standard object (class), or even a (tied) glob and the "singleton pattern' has achieved nothing.
That is because the solutions offered override the 'singleton pattern', whose sole purpose is to avoid sharing through globals (even if disguised behind a function interface). In order to be using the 'singleton pattern' as it is intended, it is necessary to re-aquire access to the singleton resource, via it's interface, at each point (or scope) in the application. Each class in the application should instantiate it's own instance of the logger either on-demand, or as a instance (or class) variable (or method).
Following the 'singleton pattern' therefore requires embedding the invarients in multiple places. Either within the constructors of all the classes that will use the resource, or in the parameters to those constructors.
You've suggested that this embedding of invarients in multiple places can be avoided by using a symbolic constant, which I agree is another perfectly practical solution, but all you have done is to move the invarient behind a different label--which also has global scope.
A rose by any other name...
I also suggest that all these solutions work equally well if the class of the logger object is any normal class that, given the same values to it's constructor returns the same instance. The 'singleton pattern' servers only to make a special case of something that doesn't need a special case.
It is also the case that all the various ways of allowing code to be written to share a single resource, without hardcoding the name of that resource all over the codebase, could equally return a glob. And by returning a glob rather than an object, it would allow the users of the logger to use all the standard Perl tools available for formatting, and print(f)ing to globs, rather than having to reinvent these in each module, or rely on the logging object to provide methods for access to all of them.
It would also allow programs that start off logging to a file they opened in the normal way, to 'upgrade' to using the logger, by simply tieing the glob to the logging object, instead of opening the file. So retroactively gaining access to all the features of the logger without having to recode each individual line of logging to use an alternative interface.
In reply to Re^3: Log::Log4perl and singleton design issue
by BrowserUk
in thread Log::Log4perl and singleton design issue
by BUU
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |