Thursday, April 12, 2012

Practical Patterns 1: Singleton

As I've mentioned before, patterns are practically a way of life for modern software developers. But too many programmers are still unfamiliar with them, even as they unknowingly use (or worse, re-invent) them. This series hopes to provide a solid introduction to pattern development in C#.

For the first entry in this series, I wanted to start simple, with one of the most popular design patterns: the Singleton. This is a pattern that many developers are familiar with, even those otherwise unaware of design patterns in general. This should give us a nice, gentle introduction into the topic. Even so, there's a lot of detail here that is often overlooked. (Singletons are also one of the most commonly poorly implemented patterns.)

As this is the first post in the series, I'm still working out the format. For now, each post will discuss a single pattern, broken down into the following segments:
  • Who - The name and basic description of the patter.
  • What - A longer description of the patterns behavior, requirements, and purpose.
  • When - Major use cases and types of problems this pattern can solve.
  • Where - The kind of applications, frameworks, and other patterns where this pattern is often found.
  • Why - The reason we apply this pattern to solve a problem, as opposed to other possible solutions.
  • How - A detailed implementation of this pattern in C#, and how it was derived.
So, lets get to it.

Who

The Singleton Pattern: A pattern describing unique or globally shared entities.

What

The Singleton is an object creation pattern that regulates the creation of instances of a given class. Specifically, the class that is being modeled by the Singleton pattern (the Singleton class) can only be created once during the execution of the application. (There are variations on this pattern which allow a small, fixed number of instances, a pool, which will be covered in a future post.)

A Singleton is different from other object creation pattern in that consumers of the Singleton class need not be aware of the state of the Singleton. Code that is accessing the singleton does not see any difference between a newly-created instance and a reference to a previously existing one. Apart from the shared nature of the state, this instance (the Singleton instance, or just the singleton) behaves just like any other object instance.

More formally, an implementation of the Singleton pattern should exhibit the following behaviors:
  • At any given time, there must be at most one live instance of the Singleton class.
  • This instance must behave like any other object instance: it must be possible to store references to it, or pass it as a parameter.
  • The first attempt to create or access an instance of the Singleton class must create a new instance and make it available.
  • Subsequent attempts to create or access an instance of the Singleton class must return the existing instance.
  • Consumers of the singleton instance should not need any special knowledge of its state; in particular, creating the first instance and accessing subsequent instances must behave the same.
One often-overlooked facet of the Singleton pattern is the idea that consumers should be able to inherit from the Singleton class and gain the benefits of the pattern with specialized behavior. Most implementations of the Singleton pattern in C# don't take this into account (or explicitly prohibit it), which is unfortunate. Many other patterns can be implemented quite elegantly when given an extensible Singleton to work with.

When

The Singleton is one of the more broadly useful patterns, but there are a couple of use cases for which Singleton is particularly well suited: global data storage, and regulating shared resources.

In a pure object-oriented language like C#, all data must belong to a class or object. Globally scoped variables don't exist. Even in languages where globals do exist, they are generally considered poor practice. Instead, we rely on patterns like the Singleton to replicate their behavior. In this sense, the Singleton is essentially a global container for all of the state information we would otherwise have put into global variables. In a naive implementation, there may be no practical difference between the two, but the fact that a Singleton is an object gives us the flexibility to impose more restrictive access controls on that state information, use property accessors to intercept data access, etc.

The other main use for Singletons is regulating access to external resources that are otherwise outside your control. This is a less clear-cut use case, because often there is no need for a true Singleton to manage such resources. For example, the .NET Framework implements classes such as Console and Application as pure static classes, and do not permit any instances of those classes to exist. As we will see later, there are situations where a static class isn't sufficient, and a Singleton class is a good alternative.

Where

Singleton patterns are found almost unversally, in any type of application. Oddly enough, there are very few actual Singleton classes in the .NET Base Class Library (which prefers pure static classes, as mentioned previously). The WPF version of the Application class (unlike the Windows Forms one) is a true Singleton, with an Application.Current instance property. The WCF service model includes support for a Singleton service class, using the InstanceContextMode.Single setting. In this case, you don't have to worry about any of the implementation details of the pattern, since the WCF runtime handles the construction of service instances on your behalf.

Singleton patterns appear in a number of more complex patterns, since they provide a simple, well-known but extensible entry point. For example, many Factory pattern implementations use a Singleton Factory, or perhaps a Singleton collection of Factories.

Why

As mentioned a few times already, there are a couple of alternatives to using a Singleton that can often solve the same problems.

The simplest solution to many such problems is to use global variables to hold state. There's a whole slew of reasons why global variables are a bad solution to most problems, compared to objects, and all of them apply here. The Singleton pattern, being a class-based solution, gives us all of the normal benefits of properties over global variables. We can inject security, validation, monitoring, notification, and other useful behaviors into the Singleton. Used this way, a Singleton can be as simple as a global container of properties, while still encapsulating the state information inside a class.

Another alternative that's been mentioned previously is using a pure static class instead of an instantiatable Singleton class. This is a more legitimate option; in many cases such a class can solve the same problem as a Singleton with much less development overhead. Classes like Console rely on the fact that all of their state information can be obtained in real-time from the Windows API, so there is no need to track state. While the console itself is a singleton-like object, the class is little more than a wrapper around a set of external function calls. In addition, you are not expected to inherit from Console, so any code that needs to use it will have direct access to the class definition. This means there's no need to pass it as a parameter, or return it from a method call. There is also no need to account for construction of child classes.

Of course, if any of those things is a requirement, then a pure static class won't suffice. A Singleton gives you many of the same benefits while still being a full-fledged instance. Singleton classes can even inherit from base classes, or implement interfaces, and be passed as instances of those other types. Singleton classes can be decorated with attributes (making them more suitable for data contracts, or cooperating with frameworks like MEF). Unlike a static class, once it has been constructed, the Singleton behaves exactly like any other instance of a reference type.

How

There are plenty of examples of how to implement a Singleton in C#, since it is such a broadly useful class. There are actually a few different techniques you can use, based on your needs. A few particularly good explanations can be found at Microsoft's Patterns and Practices Singleton article, and Jon Skeet's C# In Depth Singleton article. I'd recommend Mr. Skeet's article in particular because it takes advantage of the Lazy<T> class in .NET 4.0. I won't rehash everything that's described there; instead, I'll try to summarize the basic points and show you a final implementation of Singleton that should work for all cases. Then I'll show what it looks like to inherit from this class.

The basic design goals of our Singleton are described above. Accomplishing some of those goals in C# should be fairly obvious. Since we want to restrict the construction of new instances, we are going to make our instance constructor private. Internally, we will keep a single private instance of the class, which represents the singleton instance that all other references point to. From that, it follows that we'll need at least one static member of the class that provides access to that underlying instance. Since C# has true properties, we may as well use that. We could also use a static method, as the C++ and Smalltalk implementations do, but a property seems more C#-ish.

Beyond that, we'd also like our Singleton to use lazy initialization, if possible. There's no reason to instantiate the Singleton instance before we use it. In fact, the deferred creation of the instance will also make it easier for us to subclass the Singleton later, as we can change the type of object that is actually instantiated before anything tries to use it. Lazy-loading used to introduce a lot of complexity into the Singleton pattern (the "best" implementation involves a nested class!) but the Lazy<T> class makes this much simpler.

Lastly, we'd really like our implementation to be thread-safe. The main problem is the guarantee that all references to our Singleton class must refer to the Singleton instance. If two or more threads happen to access our uninitialized Singleton at the same time, its possible that more than one of them will try to create the "first" instance. This is what causes most of the complexity in the pre-4.0 versions, the need to limit the instantiation of a new instance to a single thread, without imposing a lock penalty on every subsequent access. A naive (and bad) implementation might ignore those problems, and simply do this:
public static Singleton Instance
{
  get
  {
    if (Singleton.instance==null)
    {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}
Here, any thread that reaches the conditional before the private instance has been created, will subsequently create one. Whichever instance is created last will ultimately be the "one true" instance, but other threads may have already received "wrong" instances by then.

There are a few ways to make this better, but none of them are particularly straightfoward. To really get it right required an in-depth understanding of how static initialization ran; in particular, you needed to know why a class with an empty static constructor behaves differently than a class with no static constructor.

With .NET 4, none of that is really important anymore, since the Lazy<T> class is intrinsically thread-safe. The implementation becomes very simple (this first pass will explicitly prevent subclassing, for simplicity):
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance
    {
        get 
        {
            return Singleton.lazy.Value;
        }
    }

    private Singleton()
    {
    }
}
The first time anything tries to read the Instance property, .NET will run the lambda expression provided to the Lazy<Singleton> constructor (in a thread-safe manner); subsequently, it will return that same instance.

Another major benefit of this approach is that we can very easily allow our Singleton to be subclassed, by providing a "registration" function for a subclass to insert itself into the scaffolding. To do this, we also need to make the base class more suitable for inheritance, as so:
public class Singleton
{
    private static Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());

    public static void Register<T>(Func<T> initializer)
        where T : Singleton
    {
        if (Singleton.lazy.IsValueCreated)
        {
            throw new InvalidOperationException("Cannot override an already-live Singleton class.");
        }

        Singleton.lazy = new Lazy<Singleton>(initializer);
    }

    public static Singleton Instance
    {
        get 
        {
            return Singleton.lazy.Value;
        }
    }   

    protected Singleton()
    {
    }
}

public class MoreSingleton : Singleton
{
}

class Program
{
    static void Main(string[] args)
    {
        Singleton.Register(() => new MoreSingleton());
    }
}
Note that our Register function is, itself, not completely thread-safe; there's a possibility that one thread will begin the process of creating the Singleton instance, but not finish, before another thread replaces the internal lazy-loaded field with a new one. We would need to ensure that, whenever such subclassing did occur, it happened very early, before any other threads of execution had been started.

Conclusion

The Singleton pattern is one of the simplest, and most useful, of the design patterns to implement. The trick is simply knowing the features of both C# and the .NET BCL that are available to help you out. In future patterns, we'll see some more complex designs and implementations, but the basic idea behind all patterns is still the same: take advantage of existing solutions to problems that are already solved, and focus on solving the ones that are not.

Next time, we'll look at another simple and extremely common pattern, the Iterator; this one should be very familiar to any C# developer, as it's so useful it has its own keyword.

1 comments:

James said...

great articles.. I can't believe your blog articles aren't full of comments..