Singletons and inheritance

For a long time, when people have asked about having inheritance and singletons, I've stated flatly that a singleton can't be derived from. It stops being a singleton at that point. Even if the class is internal and you can prove that no other classes in the assembly do derive from the singleton and break the pattern's effect, it's still not a genuine singleton.

It was only when I was thinking about one of the comments about my enhanced enums proposal that I realised there's an alternative approach. You can derive from a singleton as nested types of the Singleton itself and still keep the private constructor. That means that the singleton nature is still contained within the body of the text which declares the singleton class, even though that text actually declares more classes. Indeed, the singleton itself can even be abstract. Here's an example:

using System;

public abstract class DataProvider
{
    static DataProvider instance = CreateDataProvider();
    
    public static DataProvider Instance
    {
        get { return instance; }
    }
    
    // Note that nested classes can call private members
    private DataProvider() {}

    public abstract void Connect();
    
    static DataProvider CreateDataProvider()
    {
        // Use Oracle on a Sunday, SQL Server otherwise
        if (DateTime.Now.DayOfWeek==DayOfWeek.Sunday)
        {
            return new OracleProvider();
        }
        else
        {
            return new SqlServerProvider();
        }
    }
    
    // Note that there's no need to make the constructors
    // for the nested types non-public, as the classes
    // themselves are private to DataProvider.
    
    class OracleProvider : DataProvider
    {
        public override void Connect()
        {
            Console.WriteLine ("Connecting to Oracle");
        }
    }

    class SqlServerProvider : DataProvider
    {
        public override void Connect()
        {
            Console.WriteLine ("Connecting to SQL Server");
        }
    }
}

I'm not suggesting you should actually use a singleton for a data provider like this - it just seemed like a simple example to demonstrate the point.

It is easy to validate that the singleton only allows one instance of DataProvider to ever be constructed. (This version isn't fully lazy, but that could be added if desired.)

It looks like I'll have to revise my statement about inheritance from now on...

Published Fri, Jan 20 2006 2:21 by skeet
Filed under:

Comments

# re: Singletons and inheritance

John:

We use a pattern very similar to the one that you described to create a factory.

Basically, we have a factory that is responsible for handing out several related types of object instances (or even other factories).

There should only ever be one of these factories in memory at any given time (singleton), but the type of the factory can change based on platform (e.g. win/web).

Monday, January 30, 2006 12:28 PM by J.Marsch

# re: Singletons and inheritance

Monday, February 06, 2006 11:36 AM by Saar Carmi

# re: Singletons and inheritance

It's not a singleton.

1) You can create a new Oracle()
2) There's nothing to stop other classes from deriving from DataProvider<T>
3) You need to know which type of DataProvider to use when you make the call. (The point of my pattern above is that you don't need to know what you're going to use.)

Monday, February 06, 2006 1:20 PM by skeet

# re: Singletons and inheritance

Hello Jon. I can see a little thing going wrong with this pattern: the DataProvider class is open for anyone to derive from it. I believe you should add a private constructor to it as you mentioned in the text.

Wednesday, February 11, 2009 2:52 PM by Hosam Aly

# re: Singletons and inheritance

@Hosam: Oops! Thanks, fixed now.

Wednesday, February 11, 2009 3:05 PM by skeet