NailYourInterview
Creational Design Patterns

Factory Design Pattern in Java with Real Example

Learn the Factory Design Pattern in Java with example. Understand problems like tight coupling and how this pattern helps improve flexibility and code reuse.

Factory Design Pattern

Video thumbnail

The Factory Pattern is a creational design pattern that allows for creating objects based on user input, without exposing the object creation logic to the client.

This pattern is useful when you want to centralize object creation while keeping the client code clean and easy to manage.

Real-Life Example — Clash of Clans

Factory Design Pattern Example
Factory Design Pattern Example

If you've ever played Clash of Clans, you already have an intuitive understanding of the Factory Pattern.

In the game, you train different troops such as Barbarians, Archers, Hog Riders, and Wizards. To create a troop, you simply visit the Barracks, select the troop you want, and it gets created for you.

Here’s the catch: You don't build the troop yourself. The Barracks handles the creation process.

That's essentially how a Factory works in programming!

Problems without Factory Design Pattern

Let’s take a look at the code without using a Factory.

We start with the abstract Troop class and its concrete implementations, like Wizard, Archer, and others.

public abstract class Troop {
    @Getter
    protected String name;
    @Getter
    protected int health;
    protected int damage;
 
    public Troop(String name, int health, int damage) {
        this.name = name;
        this.health = health;
        this.damage = damage;
    }
 
    public abstract void attack();
    public abstract void move();
}

Now, here’s the issue: The client code involves manual if-else object creation. Take a look at the messy code:

Client1.java
public class Client1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
 
        System.out.println("Enter troop type (Barbarian, Archer, Wizard, HogRider):");
        String type = scanner.nextLine();
 
        Troop troop;
 
        if (type.equalsIgnoreCase("Barbarian")) { 
            troop = new Barbarian(); 
        } else if (type.equalsIgnoreCase("Archer")) { 
            troop = new Archer(); 
        } else if (type.equalsIgnoreCase("Wizard")) { 
            troop = new Wizard(); 
        } else if (type.equalsIgnoreCase("HogRider")) { 
            troop = new HogRider(); 
        } else { 
            throw new IllegalArgumentException("Unknown troop type: " + type); 
        } 
 
        troop.move();
        troop.attack();
 
        scanner.close();
    }
}

The Problems with This Approach

Same messy if-else repeated across multiple clients.

Currently, we have just 4 troops. But imagine having hundreds of troops — the if-else logic would be massive!

Adding a new troop (like Giant) would require updating every client manually.

You’d need to add it to each client that’s using the if-else logic.

Code becomes hard to maintain and error-prone.

With so much repetition, mistakes are bound to happen.

Solution: Using the Factory Pattern

Instead of scattering the object creation logic across multiple places, we centralize it in a Factory class.

Now, the Client code looks much cleaner:

public class Client1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
 
        System.out.println("Enter troop type (Barbarian, Archer, Wizard, HogRider):");
        String type = scanner.nextLine();
 
        Troop troop = TroopFactory.createTroop(type); // Centralized object creation
 
        Troop troop;
 
        if (type.equalsIgnoreCase("Barbarian")) {
            troop = new Barbarian();
        } else if (type.equalsIgnoreCase("Archer")) {
            troop = new Archer();
        } else if (type.equalsIgnoreCase("Wizard")) {
            troop = new Wizard();
        } else if (type.equalsIgnoreCase("HogRider")) {
            troop = new HogRider();
        } else {
            throw new IllegalArgumentException("Unknown troop type: " + type);
        }
 
        troop.move();
        troop.attack();
 
        scanner.close();
    }
}

Now, adding a new troop (like "Giant") only requires changes to the TroopFactory, not every client.

It’s a good practice to use an enum in combination with the Factory pattern to eliminate errors in the if-else logic. With enums, you can avoid potential mistakes and keep things more streamlined.

UML

Here’s a simple UML representation for the Factory Design Pattern:

UML for Factory Design Pattern
UML for Factory Design Pattern

In the UML:

  • Barbarian, Archer, Wizard, and HogRider all inherit from Troop (is-a relationship).

  • Client depends on the Factory (has-a relationship).

  • Factory creates objects and returns them as the Troop type.

Key Benefits of Using the Factory Design Pattern

On this page