Singleton Pattern

Definition:

"A class must have single instance and provide a global point of access to the class"

How do you achieve a class as Singleton Pattern?

  • Declare the constructor of a class to be private.
  • Define a static method or static property as public and that returns a reference to the instance.

Aim:

Create single instance for getting meal number from MealNumberGenerator class instead of creating multiple instance of MealNumberGenerator class.

Use case:

The unique meal number needs to be generated whenever meal is added into repository. Meal information shall be added using 'Add Meal' menu option and 'Export Meal' option. The system needs to instantiate MealNumberGenerator class instance from two different places, 'Add Meal' menu option and 'Export Meal' option.
We shall create one instance of MealNumberGenerator class and get the meal number even if the user tried to create instance from different places,'Add Meal' menu option and 'Export Meal' option.
Generating meal number has specific format like "BMA001" and first character 'B' indicates Breakfast, second character 'M' indicates main course, thrid character 'A' indicates American cuisine.

Problem Statement:

Creating two instance of MealNumberGenerator class shall not be good design in this usecase. Generating meal number may be needed in some other places near future, then we may end up creating new instances in all those places.

Solution for Problem Statement:

Creating single instance for MealNumberGenerator class and providing global access point to GetMealNumber method helps to solve the problem statement issue.

Example without Singleton Pattern:

No Singleton Pattern

MealNumberGenerator : class is having GetMealNumber method, responsible for generating unique meal number based on existing MealType, MealCourses and CuisineType available in repository.

NoSingletonPattern : class creating two MealNumberGenerator instances for getting meal number for Pancake and Honey Buttermilk Biscuits.

public enum MealType
{
    Breakfast = 1,
    Lunch = 2,
    Dinner = 3,
    Snack = 4,
}

public enum MealCourses
{
    MainCourse = 1,
    Side = 2,
    Soup = 3,
    Appetizer = 4,
    Salad = 5,
    Dessert = 6,
    Drink = 7
}

public enum CuisineType
{
    American = 1,
    Asian = 2,
    European = 3,
    Oceanian = 4
}

public class Meal
{
    public string MealId { get; set; }
    public string MealName { get; set; }
    public MealType MealType { get; set; }
    public MealCourses MealCourse { get; set; }
    public CuisineType CuisineType { get; set; }
}

//Generate alphanumeric number for adding meal into repository 
public class MealNumberGenerator
{
    public string GetMealNumber(MealType mealType, MealCourses mealCourses, CuisineType cuisineType)
    {
        //Generate meal number based on existing MealType, MealCourses and CuisineType available in repository
        return "BMA001";
    }
}

class NoSingletonPattern
{
    static void Main(string[] args)
    {
        //Adding meal information from 'Add Meal' menu
        //Adding Pancake into Repository
        Meal meal1 = new Meal();
        MealNumberGenerator mealNumberGeneratorInstance1 = new MealNumberGenerator();
        meal1.MealId = mealNumberGeneratorInstance1.GetMealNumber(MealType.Breakfast, MealCourses.MainCourse, CuisineType.American);
        meal1.MealName = "Pancake";
        meal1.MealType = MealType.Breakfast;
        meal1.MealCourse = MealCourses.MainCourse;
        meal1.CuisineType = CuisineType.American;

        //Adding meal information from 'Export Meal' option
        //Adding Honey Buttermilk Biscuits into Repository
        Meal meal2 = new Meal();
        MealNumberGenerator mealNumberGeneratorInstance2 = new MealNumberGenerator();
        meal2.MealId = mealNumberGeneratorInstance2.GetMealNumber(MealType.Breakfast, MealCourses.Side, CuisineType.American);
        meal2.MealName = "Honey Buttermilk Biscuits";
        meal2.MealType = MealType.Breakfast;
        meal2.MealCourse = MealCourses.Side;
        meal2.CuisineType = CuisineType.American;

        Console.ReadLine();
    }
}
        

Example with Singleton Pattern:

Singleton Pattern

MealNumberGenerator : Singleton class is having GetMealNumber method, responsible for generating unique meal number based on existing MealType, MealCourses and CuisineType available in repository.

SingletonPattern : class creating one instance of MealNumberGenerator class, getting meal number for Pancake and Honey Buttermilk Biscuits. GetMealNumber method provides global point of access for getting instance of MealNumberGenerator class.

//Generate alphanumeric number for adding meal into repository 
public class MealNumberGenerator
{
    private static MealNumberGenerator mealNumberGenerator = null;

    static MealNumberGenerator()
    {

    }

    private static object lockObject = new object();

    public static MealNumberGenerator GetMealGeneratorInstance
    {
        get
        {
            lock (lockObject)
            {
                if (mealNumberGenerator == null)
                    mealNumberGenerator = new MealNumberGenerator();

                return mealNumberGenerator;
            }
        }
    }

    public string GetMealNumber(MealType mealType, MealCourses mealCourses, CuisineType cuisineType)
    {            
        //Generate meal number based on existing MealType, MealCourses and CuisineType available in repository
        return "BMA001";
    }
}

public class SingletonPattern
{
    static void Main(string[] args)
    {
            

        //Adding meal information from 'Add Meal' menu
        //Adding Pancake into Repository
        Meal meal1 = new Meal();
        MealNumberGenerator mealNumberGeneratorInstance1 = MealNumberGenerator.GetMealGeneratorInstance;
        meal1.MealId = mealNumberGeneratorInstance1.GetMealNumber(MealType.Breakfast, MealCourses.MainCourse, CuisineType.American);
        meal1.MealName = "Pancake";
        meal1.MealType = MealType.Breakfast;
        meal1.MealCourse = MealCourses.MainCourse;
        meal1.CuisineType = CuisineType.American;

        //Adding meal information from 'Export Meal' option
        //Adding Honey Buttermilk Biscuits into Repository
        Meal meal2 = new Meal();
        MealNumberGenerator mealNumberGeneratorInstance2 = MealNumberGenerator.GetMealGeneratorInstance;
        meal2.MealId = mealNumberGeneratorInstance2.GetMealNumber(MealType.Breakfast, MealCourses.Side, CuisineType.American);
        meal2.MealName = "Honey Buttermilk Biscuits";
        meal2.MealType = MealType.Breakfast;
        meal2.MealCourse = MealCourses.Side;
        meal2.CuisineType = CuisineType.American;

        Console.ReadLine();
    }
}