The Factory Method Pattern is a creational design pattern that provides an interface for creating objects, but allows subclasses to alter the type of objects that will be created. Instead of calling a constructor directly to create an object, the factory method delegates the creation to subclasses or derived classes, allowing for more flexibility and decoupling in object creation.
Key Concepts:
- Factory Method: Defines an interface or abstract method for creating an object, but lets subclasses decide which class to instantiate. Thus, the method is deferred to subclasses.
- Product: The object that is created. The factory method defines the type of product (typically an interface or an abstract class).
- Concrete Product: The actual object that is created by the factory method, typically implementing the Product interface or extending the Product abstract class.
- Creator (Factory): Declares the factory method that returns a product object. It may also include default implementations.
- Concrete Creator (Concrete Factory): Overrides the factory method to create and return a specific type of product.
Structure of the Factory Method Pattern:
- Creator: This class declares the factory method, which returns an object of type
Product
. - ConcreteCreator: This subclass implements the factory method to return an instance of
ConcreteProduct
. - Product: This is the interface or abstract class for objects created by the factory method.
- ConcreteProduct: This is a class that implements the
Product
interface.
When to use the Factory Method Pattern:
- When the exact class of objects to be created is not known until runtime.
- When you want to decouple the code that creates objects from the code that uses objects.
- When a class wants its subclasses to specify the objects to be created.
- When you have a class with multiple potential subclasses, and you want to delegate object creation based on some criteria.
Example Scenario:
Let’s say you are building a logistics system, and you want to have different transportation modes like trucks and ships. The transportation mode might be chosen at runtime, depending on factors like the type of goods, location, or cost. You can use the Factory Method to handle the creation of the appropriate transportation mode.
Example Code:
Step 1: Define the Product Interface
Step 2: Implement Concrete Products
Step 3: Define the Creator (Factory) with the Factory Method
Step 4: Implement Concrete Creators (Concrete Factories)
Step 5: Client Code
The client code interacts with the factory to get the right product (transportation mode). It is decoupled from the actual classes of the products being created.
Output:
Road logistics:
Delivering by land in a truck.
Sea logistics:
Delivering by sea in a ship.
Explanation:
- Product Interface (
Transport
): Defines the general behavior (i.e., thedeliver
method). - Concrete Products (
Truck
,Ship
): Implements the behavior for specific types of products (i.e., different delivery methods). - Creator (
Logistics
): Declares the factory methodcreate_transport()
that returns aTransport
object. - Concrete Creators (
RoadLogistics
,SeaLogistics
): Override the factory method to instantiate specific products (Truck
orShip
). - Client Code: Works with the factory (i.e.,
Logistics
) to create the appropriate object and execute the corresponding method (deliver
).
When to Use Factory Method:
-
When you don’t know beforehand which exact class of objects your system will need: If the exact class of the object that will be created is determined at runtime (based on some conditions), the Factory Method is a good fit.
- Example: If you’re building a notification system, and at runtime you decide whether to send an email, SMS, or push notification, the Factory Method would help create the appropriate notification sender without hardcoding any specific classes.
-
When you want to decouple object creation from the client code: If you want to centralize the creation of objects in a specific place (the factory) and let the client interact with abstract interfaces, this pattern works well.
- Example: In a game engine, different character types (e.g., Warrior, Mage, Archer) might be created at different points in the game. The game logic would only interact with the abstract
Character
class, and the Factory Method would handle creating the right type of character.
- Example: In a game engine, different character types (e.g., Warrior, Mage, Archer) might be created at different points in the game. The game logic would only interact with the abstract
-
When you want to follow the Open/Closed Principle: If you anticipate adding new product types or variants in the future, the Factory Method allows you to do so without modifying existing code.
- Example: In the logistics example, if you later introduce
AirLogistics
, you can add a newAirLogistics
class without changing the existing code that handlesRoadLogistics
orSeaLogistics
.
- Example: In the logistics example, if you later introduce
Difference from Abstract Factory:
- Factory Method creates a single product (one type of object), and subclasses decide which concrete class to instantiate.
- Abstract Factory creates a family of related objects, and subclasses determine which concrete classes to instantiate for all products in the family.
The Factory Method is useful when you need flexibility in object creation without exposing the concrete classes to the client code, while the Abstract Factory is useful when creating families of related objects.