1. Introduction
It defines an interface for creating an object, but lets subclasses decide which class to instantiate. The Factory Method pattern lets a class defer instantiation to subclasses.
Key Features:
- Interface Definition: The pattern provides a common interface or method for object creation.
- Subclass Responsibility: Subclasses override the factory method to create specific types of objects.
- Deferred Instantiation: The responsibility for instantiating objects is deferred to subclasses, promoting flexibility and scalability.
You begin with an abstract creator class, commonly referred to as the creator, which establishes the fundamental framework of the application. The subclasses that extend this abstract class are tasked with handling the specific object creation process.
2. Example
Structure:
- Creator (Abstract Class or Interface): Declares the factory method that returns an object. The default implementation may return a general object or none at all.
- Concrete Creator (Subclass): Implements the factory method to create and return a specific object.
- Product (Abstract Class or Interface): Defines the interface for the objects the factory method creates.
- Concrete Product: Implements the Product interface.
Example in Java:
Here’s an example using the Factory Method pattern:
// Product interface interface Product { void use(); } // Concrete Product A class ConcreteProductA implements Product { @Override public void use() { System.out.println("Using Product A"); } } // Concrete Product B class ConcreteProductB implements Product { @Override public void use() { System.out.println("Using Product B"); } } // Creator (Factory) abstract class Creator { public abstract Product createProduct(); public void someOperation() { Product product = createProduct(); product.use(); } } // Concrete Creator A class ConcreteCreatorA extends Creator { @Override public Product createProduct() { return new ConcreteProductA(); } } // Concrete Creator B class ConcreteCreatorB extends Creator { @Override public Product createProduct() { return new ConcreteProductB(); } } // Client Code public class FactoryMethodExample { public static void main(String[] args) { Creator creatorA = new ConcreteCreatorA(); creatorA.someOperation(); // Outputs: Using Product A Creator creatorB = new ConcreteCreatorB(); creatorB.someOperation(); // Outputs: Using Product B } }
3. Benefits
- Promotes Open/Closed Principle: The Factory Method pattern makes it easy to add new product types without modifying existing code. Just add a new subclass and override the factory method.
- Encapsulates Object Creation: The creation logic is encapsulated in subclasses, keeping the client code simple and clean.
- Increased Flexibility: The client does not need to know the specific class being instantiated, making the application more flexible and extensible.
- Code Reusability: Common behavior for object creation can be centralized in the base class while allowing specialized creation in subclasses.
4. When to Use
- When you want to delegate the responsibility of object creation to subclasses.
- When the class instantiating objects should not have knowledge about the specific types being created.
- When adding new types of products requires minimal changes to the codebase (Open/Closed Principle).
- When your application involves a family of products sharing a common interface or abstract class.
5. Factory Method vs. Simple Factory
Aspect | Factory Method | Simple Factory |
Object Creation | Delegates object creation to subclasses. | Centralized in a single factory class. |
Flexibility | High flexibility; easy to add new product types. | Less flexible; adding new product types requires modifying the factory. |
Open/Closed Principle | Complies with Open/Closed Principle. | Violates Open/Closed Principle if new types are added. |
Complexity | More complex due to subclassing and overriding. | Simpler to implement and use. |
Use Case | Useful for complex hierarchies or families of products. | Useful for applications with a fixed number of product types. |
Extensibility | Highly extensible with minimal code changes. | Limited extensibility without modifying the factory. |