Creational Patterns (Factory & Singleton)
Learn how to control object creation to make your system more flexible and manageable using Singleton and Factory patterns.
Learning Goals
- Implement a thread-safe Singleton pattern.
- Decouple object creation logic using the Factory Method pattern.
- Identify scenarios where creational patterns solve common instantiation issues.
Mastering Object Creation
Creational design patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation (new Object()) can often lead to design problems or added complexity to the design. Creational design patterns solve this problem by controlling this object creation.
1. The Singleton Pattern
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it.
Why use it? It is useful for managing shared resources like a database connection pool, a logging service, or a configuration manager.
Key Implementation Details:
- Private Constructor: Prevents other classes from instantiating it.
- Static Instance Variable: Holds the single instance.
- Static Access Method: Returns the instance (often creating it if it doesn't exist).
Note on Thread Safety: In multi-threaded environments, you must ensure that two threads don't create two instances simultaneously. Use "Double-Checked Locking" or "Static Initialization" to prevent this.
2. The Factory Method Pattern
The Factory Method pattern defines an interface for creating an object, but let's subclasses decide which class to instantiate.
Why use it? It decouples the client code (the code using the object) from the concrete classes being instantiated. This makes it easy to add new types without changing the client.
Visualizing the Factory Pattern
Implementing a Robust Factory
- 1Step 1
Create a common interface (e.g.,
INotification) that all products will implement. This ensures a consistent contract for the client. - 2Step 2
Implement the interface in multiple classes like
SmsNotificationandEmailNotification. Each handles its own specific logic. - 3Step 3
Create a
NotificationFactoryclass with a static methodcreateNotification(type). Use a simple switch or mapping to return the correct implementation. - 4Step 4
The client no longer uses
new EmailNotification(). Instead, it callsNotificationFactory.createNotification('email'). The client now depends on theINotificationinterface, not concrete classes.
Knowledge Check
Which creational pattern is best suited for managing a single shared connection to a database?