Home
  Latest posts
  My Writings
  My Code
  My Gallery
  About me
 
  rssfeed Syndication
 
Bloggtoppen.se
 
 
Links
  Cornerstone
  SweNug
 
Post categories
  misc (48)
  Architecture (21)
  C# (19)
  Asp.Net (2)
  Vb.Net (2)
  Training (7)
  Data (19)
  Events (40)
  Platform (2)
  Orcas (4)
  Updates (3)
  Methods (10)
  Tools (6)
  Announcements (14)
  Languages (1)
  Patterns (6)
  Opinions (11)
  Fun (3)
  Ineta (1)
  Opinion (0)
  Practices (2)
  WCF (5)
 
 
 

Pattern Focus: Singelton v2.0

Wednesday, February 20, 2008

Other pattern focus posts:

Singelton is a well-used and commonly known pattern in the software development world. It's been around for a very long time and we are still using the same basic three or four rows of code to implement it over, over and over again. With some inspiration from one of my students on my LINQ course today I finally sat down and did something about it. Enter Singelton v2.0:

MyFactory factory1 = new StaticSingelton("initialization data");
MyFactory factory2 = new StaticSingelton("initialization data");

The two, factory1 and factory2, now shares the same instance of MyFactory. How did I do this? Read on to find out.

Inspired by Nullable I took on the task of creating a generic singelton class that wraps and manages the singelton instances for you. My first naive attempt look something like this:

    public class NaivSingelton
        where T: class, new()
    {
        private static T _instance;

        public T Instance {
            get {
                if (_instance == null)
                    _instance = new T();

                return _instance;
            }
        }

        public static implicit operator T(NaivSingelton value) {
            return value.Instance;
        }
    }

Which gave the simple and naive usage of:

MyFactory factory = new NaivSingelton();

However, that didn't satisfy me. I had a couple of more requirements. I wanted to change what the scope/context of the singelton should be. I also wanted be able to initialize the object with parameters and I wanted to be able to separate singelton instances based on what those parameters was. So utilizing some more generic code, the Activator class and a version of "Template Method" a simple base class took form:

 

 public abstract class Singelton
    {
        protected class KeyHolder {
            private object[] parameters;
            internal KeyHolder(object[] parameters)
            {                
                this.parameters = parameters;
            }

            public override bool Equals(object obj)
            {
                if (obj == null && parameters == null)
                    return true;
                else if (obj == null)
                    return false;
                
                if (!(obj is KeyHolder))
                    return false;


                object[] paramsToCompareWith = ((KeyHolder)obj).parameters;

                if (paramsToCompareWith.Length != parameters.Length)
                    return false;

                for (int index = 0; index < parameters.Length; index++)
                {
                    if (parameters[index] != paramsToCompareWith[index])
                        return false;
                }

                return true;                
            }

            public override int GetHashCode()
            {
                int hashCode = 0;

                foreach (var item in parameters)
                {
                    hashCode = hashCode ^ item.GetHashCode();
                }

                return hashCode;
            }
        }
        
        public Singelton() { }

        public Singelton(T initialObject)
        {
            StoredInstances[key] = initialObject;
        }

        public Singelton(params object[] initializationParameters)
        {
            InitializationParameters = initializationParameters;
        }
    
        private object[] _initializationParameters;
        private KeyHolder key = new KeyHolder(null);
         
        protected object[] InitializationParameters
        {
            get
            {
                return _initializationParameters;
            }
            set
            {
                _initializationParameters = value;
                key = new KeyHolder(value);
            }
        }

        protected abstract Dictionary StoredInstances { get; }

        public T Instance
        {
            get
            {
                if (!StoredInstances.ContainsKey(key))
                    StoredInstances[key] = CreateNewInstance();

                return StoredInstances[key];
            }
        }

        private T CreateNewInstance()
        {
            return (T)Activator.CreateInstance(typeof(T), InitializationParameters);
        }

        public static implicit operator T(Singelton value)
        {
            return value.Instance;
        }
    }

This now allowed me to create different types of singelton implementations that stored the singelton instances differently. Also using a dictionary and a separate Key class for that dictionary (thanks for the idea Roger) I was able to differentiate instances based on what initialization data that was passed to the constructor of the singelton class.

Now I could simply create new subclasses:

    public class ThreadStaticSingelton : Singelton
        where T : class
    {
        [ThreadStatic]
        private static Dictionary _storedInstances = new Dictionary();

        public ThreadStaticSingelton(T initialObject) : base(initialObject) { }
        public ThreadStaticSingelton(params object[] initializationParameters) : base(initializationParameters) { }


        protected override Dictionary StoredInstances
        {
            get
            {
                return _storedInstances;
            }            
        }
    }

And

public class StaticSingelton : Singelton
        where T : class
    {
        private static Dictionary _storedInstance = new Dictionary();
       
        public StaticSingelton(T initialObject) : base(initialObject) { }
        public StaticSingelton(params object[] initializationParameters) : base(initializationParameters) { }

        protected override Dictionary.KeyHolder, T> StoredInstances
        {
            get { return _storedInstance; }
        }
    }

Which gives me the possibility to initialize singeltons like this now:

 

            MessageClass m1 = new StaticSingelton("Hello {0}");
            m1.Say();

            MessageClass m2 = new StaticSingelton("Hello {0}");
            m2.Say();


            MessageClass m3 = new StaticSingelton("Hello 2 {0}");
            m3.Say();

            MessageClass m4 = new StaticSingelton("Hello 2 {0}");
            m4.Say();

M1 and M2 shares the same instance, while M3 and M4 shares another.

One could easily think about other possible singelton implementations that can easily extend the base singelton class and take advantage of the generic way in which it get's initialized.

You can download my example project over here: https://lowendahl.net/shoutCode.aspx

 

Comments
2/21/2008 12:18:00 AM   http://www.rogeralsing.com   -   Roger Alsing
 
You can make the KeyHolder class a bit more Linqy by replacing the following code:
if (paramsToCompareWith.Length != parameters.Length)
return false;

for (int index = 0; index < parameters.Length; index++)
{
if (parameters[index] != paramsToCompareWith[index])
return false;
}

With this:

return parameters.SequenceEqual(paramsToCompareWith)
 
2/21/2008 4:38:00 AM     -   Mike
 
What is wrong with just creating a static instance of a class?
 
2/21/2008 8:53:00 AM     -   Torkel
 
Interesting approach. One of the really nice benefits of using Castle Windsor is you get configurable singleton (i.e. lifestyle) behaviour for free.

service="MyApp.Core.Caching.ICache MyApp.Core"
type="MyApp.Core.Caching.WebSessionCache, Ebiz.Core" />

Here you can in configuration (or through code) change the lifestyle from singleton to transient or perThread, etc.


/Torkel
 
2/21/2008 9:35:00 AM   https://lowendahl.net   -   Patrik Löwendahl
 
Mike: It's nothing wrong with making a static instance of a class. But its just tedious. With this code I don't have to, alos using different subclasses I can choose what strategy should be used to store the singelton instance.
 
2/21/2008 9:36:00 AM   https://lowendahl.net   -   Patrik Löwendahl
 
Roger: Thanks :)


Comment
Title:
Your name:
Your url:
Text:
Please enter the text from the image: