Page 1 of 1

Class methods and the singleton pattern for beginners.

#1 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Posted 12 September 2010 - 05:37 AM

This tutorial was inspired by learning from other DIC members in this thread.

For more information on the singelton pattern look here.

I came across something like the singleton pattern without knowing it while I was making a program. Users were supposed to be able to create a report about the program they were using while using it. I figured I'd make a windows form separate from the rest of the application, I wanted it to be on its own as much as possible.

In this I figured that I didn't want any more references to it then absolutely necessary and I wanted it to be as easy as possible to use from the rest of my code. Could I somehow get around having to instantiate my class (the form)?

I came to think of static classes. But static classes feel a little, well, like global variables and global variables I don't like since they tend to make me produce sloppy code. So I got to experimenting with static methods in non static classes i.e. class methods.

By using a class method of a non static class I could get rid of the MyClass mc = new MyClass(); and replace it with a MyClass mc = MyClass.Make(); which isn't much of an improvement. But, if I wanted to I could even do this MyClass.Make(); which is just like a VB.NET Form1.Show(). However, doing MyClass.Make(); is questionable since I don't get any references to the object (the instance of MyClass) - there's no way to do anything with it from the rest of the code. On non graphic classes losing the reference will kill them - it won't work.

Anyway, there now is a way to easily make an object from a class without using new and in case of a Form I could even just start it and forget it.

How is this done then... For clarity I'll use very simple examples named First and Second, but they are easily extendable.

using System.Windows.Forms;

namespace ClassMethodAndSingleton
{
    public partial class Second : Form
    {
        //Notice how I made the constructor private.
        //This way you can not create an object of this
        //class without using the "Make" method.
        //It's kind of interesting I think and it will
        //soon come in handy.
        private Second()
        {
            InitializeComponent();
        }

        public static Second Make()
        {
            //Now this feels a bit weird. I use a variable
            //that lives only in this method to send back
            //a reference to this object, but it works fine.
            Second me;
            me = new Second();
            me.Show();
            return me;
        }
    }
}


And here is how I use this class
using System;
using System.Windows.Forms;

namespace ClassMethodAndSingleton
{
    public partial class First : Form
    {
        public First()
        {
            InitializeComponent();
        }

        private void btnSecond_Click(object sender, EventArgs e)
        {
            //Now, this is a bit odd, to lose the reference
            //to my object. It works but it is not good practice.
            //If you do this with a class that isn't graphic
            //(just a class of code) the object will die shortly.
            //So that is a really bad idea.
            //However with a form - if you're sure you don't
            //want to reference it any more - it can be done.
            Second.Make();
        }
    }
}



What have we here then? A class "First" that makes objects of a class "Second" and losing all references to it. Ok, for my purposes it works fine since the object I create is a form and I'm sure I never want to reference it again.

But, could I do something more with this class of mine? Suppose that I wanted to make sure that only one form of class Second is open at the same time. That seems like it could come in handy at times. How cold I achieve this?

I'd need to have a variable to keep track of if there is an object of type Second somewhere and check against it before creating an object of type Second. If it references an object (i.e. is not null) I'd not make a new object but if it was null I'd know that no object of type Second existed and I could make one.

So, where do I put this variable? A good thing would be to put it somewhere where it would be easy to find and I want to be sure it is there every time I use the class Second. Well then, lets put it within the class Second, make it static too. This way it's always there when I use the class and it will be shared among all objects of the class. :) The same reasoning goes for the code that checks if there already is an object of the class Second - I put that in the class. Wow, great, now I just need to call the method within Second to see if the static variable is null or not. If null I can create an object, otherwise not. Now, if I put this method within the code that creates the object i.e. within the Make method, everything will be really neat and clean.

using System;
using System.Windows.Forms;

namespace ClassMethodAndSingleton
{
    public partial class First : Form
    {
        //A reference to the second (the singleton) class.
        private Second sec;

        public First()
        {
            InitializeComponent();
        }

        private void btnSecond_Click(object sender, EventArgs e)
        {
            //It's good practice to have a reference to your
            //object. In most cases it's even necessary so this
            //is the proper way of doing things.
            sec = Second.Make();
        }
    }
}


using System.Windows.Forms;

//This is a demonstration of the singleton class on Forms.
namespace ClassMethodAndSingleton
{
    public partial class Second : Form
    {
        //Here is a static variable that holds a reference 
        //to an object of type Second. Since it's static it
        //can be used even when there is no instance (object)
        //of the class. It is also - which is important - the
        //same variable for all objects; they share this
        //variable. We couldn't check to see if
        //an object already exists if each object had its
        //own copy of the variable since it would always
        //be newly initiated.
        private static Second me;

        //Notice how I made the constructor private.
        //This way you can not create an object of this
        //class without using the "Make" method.
        private Second()
        {
            InitializeComponent();
        }

        public static Second Make()
        {
            //If there is no object of class Second
            //make one. If there is do nothing.
            //In either case, return a reference
            //to the object whether newly made or not.
            if (me == null)
            {
                //This might also feel weird. Using a static variable
                //of the class to hold an instance of the class, it's
                //a bit like lifting your self by pulling your hair.
                //But it works great for our purposes.
                me = new Second();
                me.Show();
            }
            return me;
        }

        //This is a special trick for Forms.
        private void Second_FormClosed(object sender, FormClosedEventArgs e)
        {
            //If you comment out this row you can't open
            //a new instance of Second, even if you've
            //closed the first.
            //This is special for Forms.
            //You don't need it in a singleton which is
            //just a code class.
            me = null;
        }

    }
}



There we are. The class "Second" is an example of the Singleton pattern. You can only open one form of class Second at a time and that is what a Singleton is.

Finally in the enclosed VS2008EE C# solution I've added the possibility to send data into the singleton: Attached File  ClassMethodAndSingleton.zip (19.17K)
Number of downloads: 143

Hope I helped someone to grasp the singleton and the beauty of (static) class methods.

Regards
Jens

PS: I'd appreciate comments on how to improve my tutorial.

Is This A Good Question/Topic? 0
  • +

Page 1 of 1