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.

Example Code: Without the factory method pattern

// 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");
    }
}

Problems with this approach

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.

Example Code: With the factory method 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.

Benefits of this approach:

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.

Summary of comparison

Feature Without Factory MethodWith Factory Method
Object creationClient 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.
CouplingTight: Client is coupled to concrete product classes.Loose: Client is coupled only to the abstract factory and product interfaces.
ExtensibilityLow: 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 complexitySimpler 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 PrincipleViolated: 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.

Share
Published by
Hassan Raza

Recent Posts

Find Intersection of Two Singly Linked Lists

You are given two singly linked lists that intersect at some node. Your task is…

6 months ago

Minimum Cost to Paint Houses with K Colors

A builder plans to construct N houses in a row, where each house can be…

6 months ago

Longest Absolute Path in File System Representation

Find the length of the longest absolute path to a file within the abstracted file…

6 months ago

Efficient Order Log Storage

You manage an e-commerce website and need to keep track of the last N order…

7 months ago

Select a Random Element from a Stream

You are given a stream of elements that is too large to fit into memory.…

7 months ago

Estimate π Using Monte Carlo Method

The formula for the area of a circle is given by πr². Use the Monte…

7 months ago