Static vs Singleton
- Static class is implicitly abstract, meaning a static class object can neither be created nor instantiated whereas singleton pattern allows us to create a single (only one) instance of a class.
- Static class is a stateless class whereas singleton class is state full
- Static class instance is created whenever it is first accessed and becomes accessible throughout the application or per appdomain whereas Singleton pattern provides flexibility that allows us to control instantiation based on the conditions; for example, instance of singleton class can be created per context like single instance of ShoppingCart can be created per customer
- Data stored in the static variable or class is shared and accessed globally throughout the application whereas singleton instance created per context is shared and accessible per context meaning data stored with in the instance created in context will not be shared or accessible from instance created in another context for example items stored in ShoppingCart will be shared and accessible among different login session of a customer but will not be accessible to another customer.
- Static class cannot be inherited or derived from any other class whereas singleton can implement interfaces and inherit from another class.
- Static class cannot be passed as a parameter to any method whereas instance of singleton class can be passed as a parameter to a method or constructor of another class.
- Only static members/fields/properties can be defined within the static class whereas singleton class allows both static and non-static members/fields/properties.
We will now look at and understand the below mentioned use case implementation that demonstrates all of the above facts.
Use Case
Let’s think about the e-commerce online web portal to which thousands of customer already have subscribed. There could be a scenario when several hundred people login at the same time out of which a few people login in to the web portal from multiple applications; i.e., web portal, mobile app or background processes then logged in customers search and add items into their shopping cart. Now think of those customers who have logged in from multiple applications and add items into the shopping cart from multiple applications.
Now the request is to provide a solution that every customer should be able to view all the items of their own private shopping cart but a specific user should be able to view all the items added in the shopping cart from different applications.
Solution
First of all we will implement a solution to have different instances of shopping cart per customer so we need three entities in the solution as mentioned below:
- ShoppingCart class that represents shopping cart. This class has a private field to store items added into the shopping cart.
- Customer class that represents a customer.
- LoggedinCustomers class that stores list a list of logged in customers
Is it possible to create instance of shopping cart per customer with static class implementation? The answer is No because static class is implicitly abstract meaning Static class object can neither be created nor instantiated. .Net CLR implicitly creates one instance of static class internally whenever it is first accessed and the same instance is shared among all other objects in an application.
Now the question arises – Is it possible to create an instance of shopping cart per customer with singleton pattern implementation? The answer is YES, we can use or implement Singleton pattern to restrict one instance created per customer, meaning instance of shopping cart that will be created for customer one will be different from instance created for customer two. Then later the same instance of shopping cart can be passed to different login sessions of customer.
Let’s follow the below mentioned steps to have this implementation in place,
- Implement a Singleton pattern in the ShoppingCart class that ensures or restricts that only one instance of shopping cart is created.
- To meet our requirement of one instance per customer, add a Boolean flag to determine whether we need to create an instance of ShoppingCart or not.
- Declare a collection object variable of type List to store items added into the Shopping Cart.
- /// <summary>
- /// An abstract representation of Shopping Cart.
- /// This class is the implementation of singleton design pattern
- /// which restricts the instantiation of a class to one object
- /// </summary>
- public sealed class ShoppingCart
- {
- private static volatile ShoppingCart _instance; //A static variable which holds a reference to the single created instance
- private static readonly object SyncRoot = new Object();
- private readonly List<string> _itemsAdded = new List<string>();
- /// <summary>
- /// private and parameterless constructor that prevents other classes from instantiating it
- /// </summary>
- private ShoppingCart() { }
- /// <summary>
- /// This method is to get the instance of ShoppingCart class
- /// </summary>
- /// <param name="bCreateInstance">This flag determines whether new instance is to be created or not</param>
- /// <returns>An instance of ShoppingCart class</returns>
- public static ShoppingCart Instance(bool bCreateInstance)
- {
- if ((_instance == null) || (bCreateInstance == true))
- {
- lock (SyncRoot)
- {
- if ((_instance == null) || (bCreateInstance == true))
- _instance = new ShoppingCart();
- }
- }
- return _instance;
- }
- /// <summary>
- /// This method is to add item into the Shopping cart
- /// </summary>
- /// <param name="itemCode"></param>
- public void AddItemToShoppingCart(string itemCode)
- {
- _itemsAdded.Add(itemCode);
- }
- /// <summary>
- /// This method is to get the list of items added into the shopping cart
- /// </summary>
- /// <returns>A list of item added into the shopping cart</returns>
- public List<string> GetShoppingCartItems()
- {
- return _itemsAdded;
- }
- }
- Now define a Customer class with a field to store an instance of ShoppingCart.
- Within the constructor of customer class create an instance of ShoppingCart class.
- Within the Customer class define a method “AddItemToShoppingCart” to add item into the ShoppingCart and method “PrintShoppingCartItem” to print all the items currently added into the shopping cart
- /// <summary>
- /// This class is a blueprint of a customer
- /// </summary>
- public class Customer
- {
- //A local variable to store an instance of ShoppingCart.
- private readonly ShoppingCart _shoppingCartInstance = null;
- #region Properties
- /// <summary>
- /// Property to hold customer name
- /// </summary>
- public string CustomerName { get; set; }
- #endregion
- #region Constructor
- /// <summary>
- /// Constructor to initialize Customer Identifier and Customer Name
- /// </summary>
- /// <param name="customerName">Customer Name</param>
- ///
- public Customer(string customerName)
- {
- CustomerName = customerName;
- _shoppingCartInstance = ShoppingCart.Instance(true);
- }
- #endregion
- /// <summary>
- /// This method is to the add item into the Shopping Cart
- /// </summary>
- /// <param name="itemCode">Item to be added into the shopping cart</param>
- public void AddItemToShoppingCart(string itemCode)
- {
- _shoppingCartInstance.AddItemToShoppingCart(itemCode);
- }
- /// <summary>
- /// This method is to print the items currently added into the shopping cart
- /// </summary>
- public void PrintShoppingCartItem()
- {
- List<string> itemsAdded = _shoppingCartInstance.GetShoppingCartItems();
- StringBuilder itemsAddedToShoppingCart = new StringBuilder();
- foreach (var item in itemsAdded)
- {
- if (itemsAddedToShoppingCart.Length > 0)
- itemsAddedToShoppingCart.Append(", ");
- itemsAddedToShoppingCart.Append(item);
- }
- Console.WriteLine("Items Added in {0}'s Cart : {1}", CustomerName, itemsAddedToShoppingCart.ToString());
- }
- }
- Now define a class named LoggedinCustomers.
- Define a field “_customers” within the LoggedinCustomers class which contains a collection of logged in Customer objects. Defined a method named “AddCustomer” to add a customer into the collection object field. Defined a method named “” to get the list of customer objects stored in the collection object
- public class LoggedinCustomers
- {
- private readonly List<Customer> _customers = new List<Customer>();
- /// <summary>
- /// This method is to get the customer from loggedin customer collection based on the customer name
- /// </summary>
- /// <param name="customerName">Customer Name</param>
- /// <returns>An instance of customer</returns>
- public Customer GetCustomer(string customerName)
- {
- Customer customer = _customers.FirstOrDefault(x => x.CustomerName == customerName);
- return customer;
- }
- /// <summary>
- /// This method is to add customer into the loggedin customer collection
- /// </summary>
- /// <param name="customer">an instance of customer class</param>
- public void AddCustomer(Customer customer)
- {
- _customers?.Add(customer);
- }
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- public List<Customer> GetCustomers()
- {
- return _customers;
- }
- }
Now write a program that instantiates an instance of Customer class for different users whereas retrieves an existing instance of customer class from a list of logged in customers maintained. This way we will be able to create different instances of shopping cart per customer and add item into the shopping cart.
Code Snippet
- public static void StartProcess()
- {
- LoggedinCustomers loggedinCustomers = new LoggedinCustomers();
- while (true)
- {
- Console.Clear();
- PrintLoggedinCustomers(loggedinCustomers);
- Console.Write("Enter 1 to login or 0 to logout from the application: ");
- string input = Console.ReadLine();
- if (input == "1")
- {
- var currentCustomer = LoginCustomer(loggedinCustomers);
- Console.WriteLine("{0} logged in sucessfully!! Let's Start Shopping ", currentCustomer.CustomerName);
- StartShopping(currentCustomer);
- }
- else
- {
- break;
- }
- }
- }
- private static Customer LoginCustomer(LoggedinCustomers loggedinCustomers)
- {
- Console.Write("Enter Customer Name to login: ");
- string customerName = Console.ReadLine();
- //search if the entered customer is already logged in then use the object
- var currentCustomer = loggedinCustomers.GetCustomer(customerName);
- //If the entered customer is not loggedin already then create a new instance
- if (null == currentCustomer)
- {
- currentCustomer = new Customer(customerName);
- loggedinCustomers.AddCustomer(currentCustomer);
- }
- return currentCustomer;
- }
- private static void PrintLoggedinCustomers(LoggedinCustomers loggedinCustomers)
- {
- var customers = loggedinCustomers.GetCustomers();
- if (0 >= customers.Count)
- {
- Console.WriteLine("No Customer is currently logged in to the application");
- }
- else
- {
- foreach (Customer customer in customers)
- {
- Console.WriteLine("{0} is currently logged in", customer.CustomerName);
- customer.PrintShoppingCartItem();
- }
- }
- }
- private static void StartShopping(Customer customer)
- {
- Console.WriteLine("Enter 0 to logout from the application");
- Console.WriteLine("Enter 1 to Print Shopping Cart Item");
- Console.WriteLine("Enter 2 to add item into the shopping cart");
- string line;
- while ((line = Console.ReadLine()) != "0")
- {
- if (line == "1")
- {
- customer.PrintShoppingCartItem();
- }
- else if (line == "2")
- {
- Console.WriteLine("Enter 9 to Stop Shopping else add Item Name to Add into the shopping cart else");
- Console.WriteLine("");
- string itemCode;
- while ((itemCode = Console.ReadLine()) != "9")
- {
- customer.AddItemToShoppingCart(itemCode);
- }
- Console.WriteLine("Enter 0 to logout from the application");
- Console.WriteLine("Enter 1 to Print Shopping Cart Item");
- Console.WriteLine("Enter 2 to add item into the shopping cart");
- }
- }
- }
Output
Two customers named “User1” and “User2” logged into the application. Both of them added different items into the shopping cart and we can view their shopping cart in the below image.

Now we will make the changes to share the same instance for all the login session of a customer. For this we will require CustomerLoginSession class that represents a login session for a customer. A customer can login from different platforms or applications i.e., Web Application or Mobile Application
Let’s follow the below mentioned steps to have this implementation in place:
- Define a class named “CustomerLoginSession” to represent customer login session. This class will have a field named “_shoppingCartInstance” of type ShoppingCart to hold a reference of ShoppingCart instance created in Customer Class. Customer Class will pass an object as a parameter to the constructor of CustomerLoginSession class.
- Within the CustomerLoginSession class define a method “AddItemToShoppingCart” to add item into the ShoppingCart.
- public class CustomerLoginSession
- {
- // An instance of ShoppingCart
- private readonly ShoppingCart _shoppingCartInstance = null;
- private readonly string _customerName;
- public string ApplicationId { get; set; }
- /// <summary>
- /// Default Constructor to initialize Customer Session
- /// </summary>
- /// <param name="instance">An instance of singleton class which is passed as a parameter</param>
- /// <param name="customerLoginApplicationId">Unique Login Session Identifier</param>
- /// <param name="customerName">Customer Name</param>
- public CustomerLoginSession(ShoppingCart instance, string customerLoginApplicationId, string customerName)
- {
- _shoppingCartInstance = instance;
- ApplicationId = customerLoginApplicationId;
- _customerName = customerName;
- }
- /// <summary>
- /// This method is to the add item into the Shopping Cart
- /// </summary>
- /// <param name="itemCode">Item to be added into the shopping cart</param>
- public void AddItemToShoppingCart(string itemCode)
- {
- _shoppingCartInstance.AddItemToShoppingCart(itemCode);
- Console.WriteLine("{0} added into {1} Cart from {2} ", itemCode, _customerName, ApplicationId);
- }
- }
- Define a field “_customerLoginSessions” within the Customer class which contains a collection of CustomerLoginSession objects because Customer can have multiple login sessions (1-to-many * multiplicity
- //A list of customer login sessions
- private readonly List<CustomerLoginSession> _customerLoginSessions = new List<CustomerLoginSession>();
- Define a property named “CurrentCustomerLoginSession” of type CustomerLoginSession within the Customer class to store current login session. In real implementation we don’t require this property. I have created to keep this project simple.
- private CustomerLoginSession CurrentCustomerLoginSession { get; set; }
- Update method “AddItemToShoppingCart” within the Customer class to make a call to the method “AddItemToShoppingCart” to CurrentCustomerLoginSession object that will further add item into the ShoppingCart.
- public void AddItemToShoppingCart(string itemCode)
- {
- CurrentCustomerLoginSession.AddItemToShoppingCart(itemCode);
- }
- Add method “InitializeCustomerLoginSession” within the Customer class to instantiate CustomerLoginSession object and pass a reference of shopping cart instance created in the customer class so that each customer login session has access to the same shopping cart instance.
- public void InitializeCustomerLoginSession(string applicationId)
- {
- CustomerLoginSession loginSession = _customerLoginSessions.FirstOrDefault(x => x.ApplicationId == applicationId);
- if (null == loginSession)
- {
- loginSession = new CustomerLoginSession(_shoppingCartInstance, applicationId, CustomerName);
- _customerLoginSessions.Add(loginSession);
- }
- CurrentCustomerLoginSession = loginSession;
- }
Now write a program that instantiates an instance of Customer class for different customers whereas retrieves an existing instance of customer class from a list of logged in customers maintained but initializes customer login session for different platforms. This way we will be able to create different instances of shopping cart per customer but share the same instance of shopping cart among different customer login sessions. Customers will be able to add items into the shopping cart from different session and able to see all the items added from different sessions.
- public static void StartProcess()
- {
- LoggedinCustomers loggedinCustomers = new LoggedinCustomers();
- while (true)
- {
- Console.Clear();
- PrintLoggedinCustomers(loggedinCustomers);
- Console.Write("Enter 1 to login or 0 to exit: ");
- string input = Console.ReadLine();
- if (input == "1")
- {
- var currentCustomer = LoginCustomer(loggedinCustomers);
- StartShopping(currentCustomer);
- }
- else
- {
- break;
- }
- }
- }
- private static Customer LoginCustomer(LoggedinCustomers loggedinCustomers)
- {
- Console.Write("Enter Customer Name to login: ");
- string customerName = Console.ReadLine();
- Console.Write("Enter Application Name Like Web Or Mobile: ");
- string application = Console.ReadLine();
- //search if the entered customer is already logged in then use the object
- var currentCustomer = loggedinCustomers.GetCustomer(customerName);
- //If the entered customer is not loggedin already then create a new instance
- if (null == currentCustomer)
- {
- currentCustomer = new Customer(customerName);
- loggedinCustomers.AddCustomer(currentCustomer);
- }
- currentCustomer.InitializeCustomerLoginSession(application);
- Console.WriteLine("{0} logged in sucessfully from {1} !! Let's Start Shopping ", currentCustomer.CustomerName, application);
- return currentCustomer;
- }
- private static void StartShopping(Customer customer)
- {
- Console.WriteLine("Enter 0 to logout from the application");
- Console.WriteLine("Enter 1 to Print Shopping Cart Item");
- Console.WriteLine("Enter 2 to add item into the shopping cart");
- string line;
- while ((line = Console.ReadLine()) != "0")
- {
- if (line == "1")
- {
- customer.PrintShoppingCartItem();
- }
- else if (line == "2")
- {
- Console.WriteLine("Enter 9 to Stop Shopping else add Item Name to Add into the shopping cart else");
- Console.WriteLine("");
- string itemCode;
- while ((itemCode = Console.ReadLine()) != "9")
- {
- customer.AddItemToShoppingCart(itemCode);
- }
- Console.WriteLine("Enter 0 to logout from the application");
- Console.WriteLine("Enter 1 to Print Shopping Cart Item");
- Console.WriteLine("Enter 2 to add item into the shopping cart");
- }
- }
- }
- private static void PrintLoggedinCustomers(LoggedinCustomers loggedinCustomers)
- {
- var customers = loggedinCustomers.GetCustomers();
- if (0 >= customers.Count)
- {
- Console.WriteLine("No Customer is currently logged in to the application");
- }
- else
- {
- foreach (Customer customer in customers)
- {
- List<CustomerLoginSession> loginSessions = customer.GetCustomerLoginSessions();
- string applications = string.Join(", ", from item in loginSessions select item.ApplicationId);
- Console.WriteLine("{0} is currently logged in from {1}", customer.CustomerName, applications);
- customer.PrintShoppingCartItem();
- }
- }
- }
Output
Customer named “User 1” logged into the application from Web and Mobile application at the same time. User added Mobile, Shoes into the shopping cart from Web Application whereas user added Jeans from Mobile Application. Finally, user could view all the items added into the shopping cart irrespective of which item was added from which application or login session.

Overall Class Structure

Conclusion
Based on the above example, I would propose to use Singleton over Static whenever we need to create instance based on some context and use Static over Singleton whenever we need the same instance or data throughout the application.

Brad KwonPosted Mar 1, 2019, 7:01 AM
Thanks for the very well-written article. I am trying to understand the Singleton pattern so please don’t get this offensive that’s what I don’t intent to. :) I just came across some thoughts while reading and testing your article. Firstly, if the singleton ShoppingCart class is instantiated per the Customer class, isn't it a violation of this pattern? <br/> As you said: Is it possible to create an instance of shopping cart per customer with singleton pattern implementation? The answer is YES And here is sort of classic article about Singleton pattern from the “C# in Dept” author: Essentially, a singleton is a class which only allows a single instance of itself to be created, (http://csharpindepth.com/articles/Singleton) Your sample code worked like a charm and all customers had their own shopping carts. So then every Customer instance has different reference of _shoppingCartInstance. So other questions popped up. Is it safe not to be collected by GC later on? And would it be better not to apply the Singleton pattern for the ShoppingCart class? I hope you don’t get my questions offensive that’s what I don’t intent to. Rather, I am just trying to understand clearly. Thank you. Best, Brad
Vinay Kumar GuptaPosted Jun 16, 2018, 12:45 PM
Thanks very useful and applicable article thanks again.