Singleton
Singleton
The Singleton Pattern (Creational) ensures a class has only one instance and provides a global point of access to that instance. It is one of the simplest design patterns in terms of its class diagram; however, its implementation requires careful consideration to handle multithreaded scenarios and ensure that only one instance is created even when multiple threads are accessing the class simultaneously.
Class diagramm
Benefits
- Controlled Access: The Singleton pattern provides strict control over how and when access to the single instance is allowed.
- Lazy Initialization: The Singleton can be configured to create its instance only when it is needed for the first time, which can contribute to reduced resource usage and improved performance.
- Global State: It can store a global state that is accessible throughout the application from a single, well-known access point.
- Substitution for Global Variables: It offers a more disciplined and namespace-friendly approach than global variables for keeping a single instance of a class.
Use Cases
Singletons are often used in scenarios where a single point of control or coordination is needed across a system. Common use cases include:
- Configuration Management: Managing application settings that need to be accessible throughout the application.
- Database Connections: Managing the connection to a database to ensure that only one connection is made, which can be reused, thus saving resources.
- Logging: Handling all logging to a single file from a single instance that provides a common logging interface.
- Caching: Storing data that is expensive to compute and should be retrieved from a single point to ensure consistency.
- Thread Pools: Managing the pool of worker threads for an application, ensuring that the pool is maintained at a single location.
How It Works
The Singleton pattern typically involves a single class which is responsible for creating its own object while making sure that only a single object gets created. This class provides a way to access its single object without the need to instantiate the object externally. The steps to implement a Singleton pattern are:
- Make the constructor private to prevent the instantiation of the class from outside.
- Create a static method that acts as a constructor. This method calls the constructor to create an instance if one doesn't exist and returns the instance.
Eager vs Lazy Loading
Eager loading and lazy loading are two strategies used in software development, particularly when dealing with databases or data retrieval, to manage how and when data is fetched from a data source like a database. These strategies help optimize performance and reduce the number of database queries made by an application.
Eager Loading
Eager loading is a strategy where related data is loaded along with the main data in a single database query.
- It anticipates that certain related data will be needed and fetches it in advance, reducing the need for additional queries in the future.
- Eager loading is often used when you know that you will need specific related data and want to minimize the number of database queries.
- It can help avoid the "N+1 query problem," where you would otherwise make a separate query for each related item.
Example: If you have a list of orders and you know you will also need the associated customer information for each order, you can use eager loading to retrieve both the orders and customer data in a single query.
Lazy Loading
Lazy loading is a strategy where related data is loaded only when it is explicitly requested by the application or when it is needed.
- It defers loading the related data until the moment it's actually accessed, which can help reduce the initial load time and save resources.
- Lazy loading is often used when you have a large amount of related data, and not all of it is needed for every operation, to avoid unnecessary data retrieval.
Example: In an e-commerce application, you might have a Product and an associated list of Reviews. With lazy loading, the reviews are not fetched from the database until the application explicitly requests them, improving performance when displaying the product list.
Implementation
The Singleton design pattern ensures that a class has only one instance and provides a global point of access to that instance. When implementing the Singleton pattern, the choice between eager and lazy loading can impact the performance and behavior of the singleton.
Eager Loading Code Example
In an eager loading Singleton, the instance is created as soon as the class is loaded or at the time of first access.
public class EagerSingleton {
// Eagerly create the instance as soon as the class is loaded.
private static readonly EagerSingleton instance = new EagerSingleton();
// Private constructor to prevent instantiation from other classes.
private EagerSingleton() { }
// Public method to access the Singleton instance.
public static EagerSingleton Instance {
get { return instance; }
}
}
...guarantees that the instance is created early and ensures thread safety, as .NET guarantees type initialization to be thread-safe.
Lazy Loading
In a lazy loading Singleton, the instance is created only when it's requested for the first time. This approach can save resources if the Singleton is not always needed.
public class LazySingleton {
private static Lazy<LazySingleton> lazyInstance = new Lazy<LazySingleton>(() => new LazySingleton());
// Private constructor to prevent instantiation from other classes.
private LazySingleton() { }
// Public method to access the Singleton instance.
public static LazySingleton Instance {
get { return lazyInstance.Value; }
}
}
...efficient in terms of resource usage because the instance is created on-demand.
Usage
EagerSingleton instance1 = EagerSingleton.Instance; EagerSingleton instance2 = EagerSingleton.Instance; Console.WriteLine(instance1 == instance2); // This should be true.
LazySingleton instance1 = LazySingleton.Instance; LazySingleton instance2 = LazySingleton.Instance; Console.WriteLine(instance1 == instance2); // This should be true.
Both the eager and lazy loading Singleton patterns ensure that only one instance of the class is created, but they differ in when and how that instance is created.