Click here to Skip to main content
Click here to Skip to main content

Tagged as

Monostate pattern

, 5 Dec 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
An interesting variation on the Singleton pattern

Introduction

An interesting variation on the Singleton pattern is the Monostate pattern, which also achieves singularity, but works through a completely different mechanism. Before we proceed any further, let me state that just like a Singleton, it too is in direct violation of the Single Responsibility Principle, in my opinion even more than the Singleton is. But it is so lovely wicked in behavior, that once in a while, you might find a good reason to use it.

Background

I have first encountered this pattern in a wonderful book, by Micah Martin and Robert C. Martin, "Agile Principles, Patterns and Practices in C#". While this pattern, or anti-pattern, has many uses, one must consider pros and cons of its implementation.

Pros: 

  • Transparency - users do not need to know that the object they use, is a Monostate.
  • Derivability -  derivatives of a Monostate continue to share static variables 
  • Polymorphism - only private static variables are shared, derivatives are free to override any methods of the base class 
  • Well-defined lifetime - being static, the variables of a Monostate have specific creation and destruction times 
Cons 

  • No conversion - you cannot derive a Monostate from a non-Monostate 
  • Efficiency - a Monostate might go through many creations and destructions, which might be quite expensive, depending on implementation 
  • Presence - even if the Monostate is never used, its variables take up space
  • Locality - they cannot be shared by multiple CLR instances
The Monostate pattern differs from Singleton, by enforcing singular behavior, without imposing constraints on structure.  

SINGLETON is best used when you have an existing class that you want to constrain through derivation and don’t mind that everyone will have to call the Instance() method to gain access. MONOSTATE is best used when you want the singular nature of the class to be transparent to the users or when you want to use polymorphic derivatives of the single object.

Martin, Micah; Martin, Robert C. (2006-07-20). Agile Principles, Patterns, and Practices in C# (Kindle Locations 6311-6313). Pearson Education. Kindle Edition.  

Using the code   

Let's take a look at this example:

public class Monostate{
    private static int x;
    public int X
    {
        get { return x; }
        set { x = value; }
    }
}

Regardless of the number of times you will create or destroy an instance of this class, there will only be one value of X, shared across all threads of your application. In other words, changes made in one of your threads are immediately and instantaneously visible in all other threads. "Big Deal!" you say, but it gets much more interesting, once we incorporate Generics and Concurrent Collections:

public class MonoConcurrentBag<T>
{
    #region Static Fields
    private static readonly ConcurrentBag<T> bag = new ConcurrentBag<T>();
    #endregion
    #region Public Properties
    public ConcurrentBag<T> Bag
    {
        get { return bag; }
    }
    #endregion
} 

Now we can proceed adding values from multiple threads and pretty much forget about any concurrency issues, or managing object lifetime.

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
internal class Program
{
    #region Methods
    private static void Main(string[] args)
    {
        Parallel.Invoke(
            () => Parallel.For(
                0,
                1000,
                i =>
                {
                    var bag = new MonoConcurrentBag<int>();
                    bag.Bag.Add(i);
                }),
            () => Parallel.For(
                0,
                1000,
                i =>
                {
                    var bag = new MonoConcurrentBag<long>();
                    bag.Bag.Add(i);
                }));
        var anotherBag = new MonoConcurrentBag<int>();
        var anotherLongBag = new MonoConcurrentBag<long>();
        Console.WriteLine(anotherBag.Bag.Count);
        Console.WriteLine(anotherLongBag.Bag.Count);
    }
    #endregion
} 

If you run this sample code, it will print two lines, each with the number 1000.

I must admit, the first time I saw this pattern, I could not wrap my head around it. After all, in every iteration of the parallel loop, I ask the system to create a new instance of the class, and at the end of it, it should be destroyed and collected by the GC, so it was difficult to comprehend, how it can survive from one thread to another.

The key takeaway in this case is that static properties of a class, can and will live longer than an instance of the class itself. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Darek Danielewski
Architect BI Software, Inc.
United States United States
A seasoned IT Professional. Programming and data processing artist. Contributor to StackOverflow.
Follow on   Twitter

Comments and Discussions

 
General[My vote of 1] TL;DR Static variables are static Pinmembercharoco5-Dec-13 6:58 
GeneralRe: [My vote of 1] TL;DR Static variables are static PinmemberDarek Danielewski5-Dec-13 7:02 
GeneralRe: [My vote of 1] TL;DR Static variables are static Pinmembercharoco5-Dec-13 10:22 
GeneralRe: [My vote of 1] TL;DR Static variables are static PinmemberDarek Danielewski9-Dec-13 14:43 
QuestionAntipattern Singleton Pinmemberwerinus5-Dec-13 5:43 
AnswerRe: Antipattern Singleton PinmemberDarek Danielewski5-Dec-13 6:13 
QuestionFlyweight PinmvpFlorian Rappl5-Dec-13 4:09 
AnswerRe: Flyweight [modified] PinmemberDarek Danielewski5-Dec-13 6:03 
QuestionHMMMM... PinmemberFatCatProgrammer5-Dec-13 3:51 
AnswerRe: HMMMM... PinmemberDarek Danielewski5-Dec-13 6:06 
GeneralRe: HMMMM... PinmemberFatCatProgrammer6-Dec-13 5:03 
GeneralInteresting PinmemberOmar Gameel Salem5-Dec-13 0:54 
GeneralRe: Interesting PinmemberDarek Danielewski5-Dec-13 6:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150327.1 | Last Updated 5 Dec 2013
Article Copyright 2013 by Darek Danielewski
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid