π Factory Method Design Pattern in Java
The Factory Method Pattern is one of the most commonly used creational design patterns. It provides a way to delegate the instantiation logic to subclasses, promoting loose coupling and scalability.
π‘ What is the Factory Method Pattern?
"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses." β Gang of Four
Itβs like giving the blueprint of object creation to a class but leaving the actual object-making to child classes.
π§ Real-World Analogy
Imagine a Logistics company. Depending on the terrain, you may want to deliver using a Truck or a Ship. The decision is made at runtime, based on client needs.
Each Logistics center (subclass) decides how to deliver:
-
RoadLogistics
β creates aTruck
-
SeaLogistics
β creates aShip
Use Case Overview
We are building a logistics management system that delivers items either by truck (land) or ship (sea). But the main client (application) doesn't know which transport will be used β it just asks logistics to "plan delivery".
1. Product Interface β Transport.java
public interface Transport {
void deliver();
}
This is the common interface for all types of transport. Each transport will define its own way to deliver()
.
2. Concrete Products β Truck.java and Ship.java
public class Truck implements Transport {
@Override
public void deliver() {
System.out.println("Deliver by land in a box.");
}
}
public class Ship implements Transport {
@Override
public void deliver() {
System.out.println("Deliver by sea in a container.");
}
}
Each class implements the Transport
interface and defines how the delivery happens.
3. Creator Class (Factory) β Logistics.java
public abstract class Logistics {
// Factory Method
public abstract Transport createTransport();
// Common logic using product
public void planDelivery() {
Transport transport = createTransport();
transport.deliver();
}
}
This is the factory class. It contains the planDelivery()
method (business logic), but it defers the object creation to the createTransport()
method β which is abstract and must be implemented by subclasses.
4. Concrete Factories β RoadLogistics.java and SeaLogistics.java
public class RoadLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Truck();
}
}
public class SeaLogistics extends Logistics {
@Override
public Transport createTransport() {
return new Ship();
}
}
These are the specific factories. Each overrides the createTransport()
method to return a specific transport type.
5. Client Code β Main.java
public class Main {
public static void main(String[] args) {
Logistics logistics;
// Land delivery
logistics = new RoadLogistics();
logistics.planDelivery(); // Output: Deliver by land in a box.
// Sea delivery
logistics = new SeaLogistics();
logistics.planDelivery(); // Output: Deliver by sea in a container.
}
}
The client (main method) is not aware of which Transport
is being used. It works with Logistics
β which provides abstraction β and delegates creation to concrete classes.
Key Advantages
-
Encapsulation of object creation: The client never knows about
Truck
orShip
directly. -
Extensible: Want to add
AirLogistics
? Just create another subclass β no need to change existing code. - Open/Closed Principle: Easy to add new types without modifying existing logic.
Consequences
- More classes and complexity
- Can be overkill for simple scenarios
When to Use
- You want to delegate the instantiation process to child classes.
- You need to localize the logic of object creation.
- You want to avoid tight coupling between the client and concrete classes.
This is Part 2 of the Java Design Patterns Series.
If you find it insightful, please share your feedback. Also let me know if you have used factory pattern in your projects.
Next Up: Abstract Factory Method Pattern β Create objects without exposing the instantiation logic!
Top comments (0)