Logger.GetInstance().Warning("Some warning",this);The GetInstance method is public static and returns the (unique-within-the-VM) instance of Logger. The Warning method is public and non-static, but the constructor's private, so the only way to get to it (the Warning method) is through the GetInstance method.
Logger is a pretty classic Singleton. In another recent project, I even made the "mistake" Steve talks about by making the Warning method public static, so I'd invoke the Warning method like this:
Logger.Warning("Some warning",this);
So maybe I take Steve's article to heart and decide that Logger should not be a Singleton. Perhaps because we want different versions of it. The only reason I can think of for wanting different versions is that maybe we want different implementations, like FileLogger and DBLogger. If that's the case, I guess we need an interface, a factory and an implementation, something like this:
ILogger (interface)With all that code roughly defined, I think we'd now use Logger like this:
public void Info(String msg,Object requester);
public void Warning(String msg,Object requester);
...
LoggerFactory (factory)
public static ILogger GetFileLogger();
public static ILogger GetFileLogger(String logfilename);
public static ILogger GetDBLogger();
public static ILogger GetDBLogger(String connectionstring);
FileLogger implements ILogger (implementation)
public FileLogger(){
super(DEFAULT_LOGFILE_NAME);
}
public FileLogger(String logfilename){
this.theLogFileName=logfilename;
}
LoggerFactory.GetFileLogger().Warning("Some warning",this);
or, more complicatedly (unless that's not a word):
String connString=ConfigHelper.GetString("logdbconnstring");Does this seem better? It's definitely more flexible in the client code, at the cost of putting more information into the client code. The client code now knows which kind of Logger it's using (FileLogger or DBLogger), which seems wrong. We could keep the client code happily ignorant of the various types of Logger by adding a "GetDefaultLogger" method to the LoggerFactory. So, if the client didn't want to override the default logger, the client would execute something like this:
LoggerFactory.GetDBLogger(connString).Warning(
"Some warning",this
);
LoggerFactory.GetDefaultLogger().Warning("Some warning",this);This seems like the best I can do, though it looks a lot like where I started from!
Log4J is the one logging framework I know a little about. It doesn't exactly use a Singleton. I think each class that wants to do logging creates a class variable (static) of type Logger on which it calls methods like "info", "warning", etc. Nevertheless, all the logging configuration happens centrally, outside of Log4J's clients.
The other place I've used Singletons is to implement DB caches. If there's a table that changes rarely and is small (for some value of "rarely" and "small"), I'll create a Singleton to hold the contents of the table.
No comments:
Post a Comment