Factory Method is a creational design pattern that deals with the object creation. It separates the object creation logic from the client code, which makes the system more flexible and maintainable. Instead of instantiating objects directly using a constructor, it passes the responsibility to another method, which is called a factory method.
In contrast, if you don’t use the factory method pattern, there will be tight coupling between client code and the concrete classes it instantiates.
In simple terms, if you do not use the factory method pattern, then you need multiple conditions and switches in the code, and on the basis of a matching condition, the object will be created or instantiated in client code. In the future, if you need any new feature, then you need to make changes in the existing code.
// Product Interface interface Vehicle { void drive(); } // Concrete Products class Car implements Vehicle { @Override public void drive() { System.out.println("Driving a car."); } } class Bike implements Vehicle { @Override public void drive() { System.out.println("Riding a bike."); } } // The "Client" that creates and uses the products class CarManufacturer { public void produceVehicle(String type) { Vehicle vehicle; if ("car".equalsIgnoreCase(type)) { vehicle = new Car(); // Direct instantiation } else if ("bike".equalsIgnoreCase(type)) { vehicle = new Bike(); // Direct instantiation } else { throw new IllegalArgumentException("Unknown vehicle type: " + type); } vehicle.drive(); } } public class WithoutFactoryDemo { public static void main(String[] args) { CarManufacturer manufacturer = new CarManufacturer(); manufacturer.produceVehicle("car"); manufacturer.produceVehicle("bike"); } }
Tight coupling: The CarManufacturer
is tightly coupled to the concrete Car
and Bike
classes. If a new Truck
class is added, the CarManufacturer
The class must be modified.
Violates Single Responsibility Principle: The CarManufacturer class has two responsibilities.
Violates Open/Closed Principle: The code is not open for extension (adding new vehicle types) without being modified (changing the createVehicle
method).
Now that you have understood the problem in the implementation of code without the Factory Method Design Pattern, let’s see how you can solve this problem using the Factory Method Design Pattern.
// Product Interface (same as before) interface Vehicle { void drive(); } // Concrete Products (same as before) class Car implements Vehicle { @Override public void drive() { System.out.println("Driving a car."); } } class Bike implements Vehicle { @Override public void drive() { System.out.println("Riding a bike."); } } // Abstract Creator abstract class VehicleFactory { // The Factory Method public abstract Vehicle createVehicle(); public void orderVehicle() { Vehicle vehicle = createVehicle(); vehicle.drive(); } } // Concrete Creators class CarFactory extends VehicleFactory { @Override public Vehicle createVehicle() { return new Car(); } } class BikeFactory extends VehicleFactory { @Override public Vehicle createVehicle() { return new Bike(); } } public class WithFactoryDemo { public static void main(String[] args) { VehicleFactory carFactory = new CarFactory(); carFactory.orderVehicle(); // Uses CarFactory to create a Car VehicleFactory bikeFactory = new BikeFactory(); bikeFactory.orderVehicle(); // Uses BikeFactory to create a Bike } }
The factory method pattern introduces an abstract VehicleFactory
with a createVehicle()
method. Subclasses like CarFactory
and BikeFactory
Then override this method to create specific products.
Loose coupling: The VehicleFactory
depends only on the Vehicle
interface, not the concrete implementations. The client code interacts with the abstract factory and product types, not the specific classes.
Adheres to the Single Responsibility Principle: Isolating the object creation part from the product and client code.
Adheres to Open/Closed Principle: To add a new vehicle type (e.g., Truck
), you just create a new TruckFactory
class without changing any existing code.
Encapsulates creation logic: The details of how an object is created are moved into the concrete factory classes, hiding them from the client.
Feature | Without Factory Method | With Factory Method |
---|---|---|
Object creation | Client code instantiates objects directly with new a keyword and uses conditional logic. | Responsibility is delegated to factory subclasses. Client uses an abstract factory to request products. |
Coupling | Tight: Client is coupled to concrete product classes. | Loose: Client is coupled only to the abstract factory and product interfaces. |
Extensibility | Low: Adding a new product requires modifying existing client code. | High: Adding a new product only requires creating a new factory subclass, leaving existing code untouched. |
Code complexity | Simpler for very small projects with few product types. Becomes more complex as conditional logic grows. | More complex initially due to extra classes/interfaces. Simplifies client code and improves long-term maintainability. |
Open/Closed Principle | Violated: The CarManufacturer must be modified to add new vehicles. | Adhered to: Open for extension, closed for modification. |
Single Responsibility Principle (SRP) | Violated: The client has a double responsibility: knowing how to create objects and using them. | Adhered to: Object creation is moved to the factory classes, leaving the client with the single responsibility of using the products. |
Thanks for reading, I hope you have learnt the concepts perfectly.
You are given two singly linked lists that intersect at some node. Your task is…
A builder plans to construct N houses in a row, where each house can be…
Find the length of the longest absolute path to a file within the abstracted file…
You manage an e-commerce website and need to keep track of the last N order…
You are given a stream of elements that is too large to fit into memory.…
The formula for the area of a circle is given by πr². Use the Monte…