This post is part of the series SOLID Wash Tunnel.
"Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance." - Refactoring Guru
Singleton is considered by many to be an anti-pattern, because it promotes the same disadvantages as global variables do. Sure they can be very handy to use, but they do break code modularity.
- It controls access to a shared resource in a multi-threaded environment.
- It saves system resources when dealing with objects that are expensive to create.
- It can be lazy initialized.
- It introduces global state, which even worst is preserved between different unrelated test cases. Which makes testing harder, and order of tests matter.
- It reduces the potential for parallelism, because of the controled access nature of the singleton.
- If the singleton is supposed to be serializable, you need to make sure only one instance is created during deserialization.
Nowdays the sigleton pattern is implemented via singleton lifetime registration. It is common to see the singleton pattern implemented in projects where there is no IoC in place, or in legacy systems.
A singleton implementation can be seen in the
SOLIDWashTunnel.Legacy project. This project is intentionally sepparated as it simulates an external service of sort (web service, library, NuGet package etc.)
The legacy project provides the
SOLIDWashTunnel with currency exchange rates information. It does so by providing a proxy which wraps the internal rate converter.
Since this "old" system does not have IoC support, and the process of authentication is time consuming, the
LegacyCurrencyRateConverterProxy class is modeled as a singleton.
- The class has been declared as
sealedso it can not be inherited, ensuring that we suddenly do not have multiple instances of the singleton (via derived classes).
- The constructor is made
privateso it can not be instantiated from outside the class.
_instanceis declared as a
private staticfield which holds the single available instance of this class.
_lockis instantiated as a simple
objectwhich prevents multiple threads from accessing
public staticproperty from which other code can access
_instancein a thread-safe way.
public sealed class LegacyCurrencyRateConverterProxy
private readonly LegacyCurrencyRateConverter _converter;
private readonly List<string> _tokens;
_converter = new LegacyCurrencyRateConverter();
_tokens = new List<string>()
private static readonly object _lock = new object();
private static LegacyCurrencyRateConverterProxy _instance;
public static LegacyCurrencyRateConverterProxy Instance
if (_instance == null)
if (_instance == null)
_instance = new LegacyCurrencyRateConverterProxy();
public ILegacyCurrencyRateConverter Authenticate(string token)
Console.WriteLine("Simulating authentication process to legacy system...");
Thread.Sleep(3000); // Simulating a time consuming authentication process to justify the singleton pattern
var user = _tokens.FirstOrDefault(x => x == token);
if (user == null)
throw new InvalidOperationException("Invalid token provided.");
The other way the singleton pattern is implemented is via singleton lifetime registration into the IoC container. Examples of this can be seen in the
ServiceRegistrations class that is housed in the root directory of the
public static class ServiceRegistrations
public static IContainer AddWashTunnel(this IContainer container)
This part of the project has been modeled intentionally to represent a legacy system that does not take into considertion SOLID principles.
Continue the series on Command Message.
If you found this article helpful please give it a share in your favorite forums 😉.
The solution project is available at GitHub.