views:

571

answers:

5

In my webapplication (C#, .Net 3.5), made up of a core class library (containing the business logic, data layer and a couple of utility classes), a windows service project, a webservice project and the website project, I have a couple of static classes in the core library used by all other projects. These classes (for example the Log class) require some initialization (They have an Initialize method) in order to set them up for usage. As an example, the Initialize method of the Log class has a directory path parameter which tells the Log, where to save the logfiles to. Alternativly I was thinking of loading the "settings" for the Log class from a configuration file in the static constructor. The drawback is, that I need different settings for unit-testing then in production code.

Is there a better way to design this? The drawback of this approach is, that all consumers of the static class will attempt to call Initialize. This is not really a problem because once initialized, the method will return immediately instead of executing the Initialize code again, but the design seems a bit weird to me.

I hope my english is sufficient to explain what I'm after. Do not hesitate to ask if the question is not clear enough.

+5  A: 

I would suggest, if the initialisation is expensive, to use a Singleton (if you're not familiar with design patterns, google Singleton Design pattern). As part of the construction of the instance, you then read in a config file, which can be specific to the environment.

This way you would get the best of both worlds.

Travis
A: 

I think you have to ask the hard questions here. Does that stuff need to be static? Static objects, whether in Singleton form or not, are pretty tough to work with. If you really need the static-ness, perhaps something like the monostate pattern can help you. It's like a polymorphic static class. Generally, all the member variables are static, while the constructors are not. Perhaps with this, you can inherit this class, and do some overriding for your needs. Just a thought.

casademora
+5  A: 

I would try to avoid static classes for things which will require initialization. Make your Log class a normal class, and perhaps have a separate factory class to create instances or a single instance. You might want to use dependency injection to avoid having any statics, although this could get painful for something like logging which is pretty universal though.

For logging in particular, both log4net and log4j (any reason you've rolled your own, btw?) use the idiom of asking some factory class for log instances based on names (commonly based on the name of the type using it). This is often stored in a static variable in each class which needs to perform logging. If the logging objects which are returned can still be affected by initialization of the logging subsystem afterwards, you don't end up with ordering concerns where the DI container has to initialize the logging framework before the logging clients are initialized etc.

Using separate logging objects instead of a static class improves testability - you can replace the logging object during a test with one which records the logs to ensure that (say) auditing information is captured. One downside of the logging objects being known statically is that this reduces the possibilities of running tests in parallel.

Apologies for the somewhat random musings - I haven't had my first coffee yet. Hopefully it's helpful though.

Jon Skeet
A: 

I think you're fine with either of the solutions you've given in your question. Either call Initialize once from your Main method (or put this in some separate SetupApplicationInfrastructure method called from Main). Or, load the settings once in the constructor.

I don't think you need to worry about trying to eliminate checking whether intialization is required or not every time the instance is accessed. It's not bad to do this.

Scott Langham
A: 

Adding to what Trav said...

In addition to your Singleton implementation of the Log, you can also wrap it around a static class. This way you wouldn't need to change the places where you're already using the static Log class. And it will be extremely easy to swap a mock Logging framework for your unit tests. I'll give an example of this in Java - assuming you have something that looks like the following:

public class Log
{
    public static void debug(Object o, String message)
    {
        System.out.println(o + " [DBUG] " + message);
    }

    public static void info(Object o, String message)
    {
        System.out.println(o + " [INFO] " + message);
    }
}

You can refactor this like the following:

public interface ILoggeer
{
    void debug(Object o, String message);
    void info(Object o, String message);
}

public class Log
{
    private static ILogger log = new ConsoleLogger();

    public static setLogger(ILogger impl)
    {
        log = impl;
    }

    public static void debug(Object o, String message)
    {
        log.debug(o, message);
    }

    public static void info(Object o, String message)
    {
        log.info(o, message);
    }
}

public class ConsoleLogger implements ILogger
{
    public void debug(Object o, String message)
    {
        System.out.println(o + " [DBUG] " + message);
    }

    public void info(Object o, String message)
    {
        System.out.println(o + " [INFO] " + message);
    }
}
Cem Catikkas