Software Design Patterns

Singleton

Singleton Pattern

Singleton(127) Ensure a class only has one instance, and provide a global point of access to it.

What does this mean?

We want to let the class control its own instantiation process. We will not create a new instance of the class, instead we will call a static function to get the only instance of class. This static function will instantiate a new instance if one has not already been created. Other functions of the class are not static, so this class can be inherited from if we need to override some functions or add new functions.

Why and when to use it?

  • Use it instead of global variables.
    • Easier to maintain.
    • 1 instance of class globally accessible.
    • Keeps your namespace cleaner.
    • Can use lazy initialization so memory not used until needed.
  • Use it instead of a class of static functions.
    • Very easy to build. Almost as easy as class of static functions.
    • Unlike static functions, subclasses can refine functions.
    • Also since you can derive classes, you can take advantage of polymorphism.

Lets take a look.

The Singleton works almost exactly like any other class except that there is only one instance* of the class so all code that references the class is always using the same instance.

The constructor is private so other classes can not instantiate the class.

All references to the class must go through a static 'Instance()' function to get a reference to the object and it's methods and properties.

* NOTE: You can allow multiple instances if you need to. You must then have more code in your 'Instance()' static function to control how many copies of the object are instantiated.

 

Sample using lazy initialization

    class Singleton_LazyInit

    {

        static Singleton_LazyInit myInstance;

      

        private Singleton_LazyInit()

        {

            //private so others can't instantiate class

        }

 

        //All code goes through here to get to functions

        public static Singleton_LazyInit Instance()

        {

            if (myInstance == null)

            { myInstance = new Singleton_LazyInit(); }

            return myInstance;

        }

       

        //Your functions can go here.

        public DateTime GetTodaysDate()

        {

            return DateTime.Now.Date;

        }

    }

 

What's wrong with it?

The code above actually has a problem. If you have 2 or more threads and the 'Instance()' function gets called at exactly the right time by 2 or more threads, you can actually end up with more than 1 instance of the class, which could cause you some headaches trying to debug the unexpected results. It would probably happen so infrequently that it would be very difficult to catch.

Making it thread safe.

There are 2 options to make this thread safe. You can use eager instantiation which is the simplest way to go, or you can used double-checked locking so that you can keep the advantages of lazy initialization(namely, conserving memory until it is needed).

Using Eager Instantiation

This is the easier thread safe instantiation method. It only saves 3 lines of code, so take a look at the double-checked locking (below, last example) too before you start coding.

    public class Singleton_EagerInit

    {

      //init just prior to first use

     static Singleton_EagerInit myInstance

                                        = new Singleton_EagerInit();

      

        private Singleton_EagerInit()

        {

            //private so others can't instantiate class

        }

 

        //All code goes through here to get to functions

        public static Singleton_EagerInit Instance()

        {          

            return myInstance;

        }

       

        //Your functions can go here.

        public DateTime GetTodaysDate()

        {

            return DateTime.Now.Date;

        }

    }

 

Double-Checked Locking

With this method you are still using lazy initialization to instantiate the class when it is first needed, but we have 3 more lines of code than the first example in order to prevent 2 or more instances from getting created simultaneously by separate threads.

This is done by locking the section of code that does a 'double-check' and then instantiates the class. Only one thread can operate in the locked block at a time and since a second check is inside of the locked block, only one instance can be created.

    public class Singleton_DblChkLck

    {

        static Singleton_DblChkLck myInstance;

        static System.Object lockBlock = new System.Object();

 

        private Singleton_DblChkLck()

        {

            //private so others can't instantiate class

        }

 

        //All code goes through here to get to functions

        public static Singleton_DblChkLck Instance()

        {

            if (myInstance == null) //single-check

            {

                lock(lockBlock)

                {

                    if(myInstance == null) //double-check

                        myInstance = new Singleton_DblChkLck();

                }

            }

            return myInstance;

        }

       

        //Your functions can go here.

        public DateTime GetTodaysDate()

        {

            return DateTime.Now.Date;

        }

    }

 

Of the three patterns above, I would strongly suggest using the last, which is the double-checked locking Singleton. The first is the simplest, but has the problem that it could be instantiated more than once if called by separate threads simultaneously. The second example would only be instantiated one time, but does not take advantage of lazy initialization. The third example takes advantage of lazy initialization, and uses a lock to prevent multiple instantiation, and it only required 3 more lines of code to implement than the first version.

How do I call a method in the Singleton?

It is very simple. You call the Instance() function which returns an instance, then you can access the public methods. Here's an example:

   string val =

   Singleton_DblChkLck.Instance().GetTodaysDate().ToString();

 

Of course that is a little longer line of code than if you just called a global variable, but we know we shouldn't use globals (right???), and if you store all your would-be global vars in a singleton, then you get to take advantage of intellisense after you type 'Instance().' and you can then choose the variable you have smartly set as property of the singleton class.

0 Comments