Factory design pattern in Java

By | July 27, 2023

Factory Design Pattern is a way of creating objects without directly specifying their exact class. Instead of creating objects using the new keyword, we hand over the object creation process to a separate factory class. This factory class is responsible for creating instances of different sub-classes or classes based on certain conditions. It helps us hide the complexity of object creation and makes our code more flexible and maintainable.

When to use Factory design pattern?

  • Complex object creation
    • When creating objects involves complex logic or initializing multiple dependencies.
  • Dependency injection
    • When you want to inject dependencies into objects, promoting better separation of concerns.
  • Decoupling object creation
    • To decouple client code from concrete class instantiation.
  • Implementing multiple product variants
    • When there are several implementations of an interface or abstract class.
  • Dynamic class loading
    • In scenarios where classes are determined at runtime or loaded dynamically.
  • Testing and Mocking
    • For creating mock objects or substitute implementations in testing environments.

Example

In this example, we use the Clash Of Clans game to understand the factory design pattern.

Factory design pattern in Java
Fig 1- Factory design pattern

As we can see above, the Factory Design Pattern is employed to create different character types with their unique powers. The game defines a common “Character” interface with methods for “selectCharacter()” and “usePower()“, which all characters must implement. Concrete classes like “Barbarian,” “Archer,” and “Wizard” are created, each representing a character type and implementing the “Character” interface with their respective powers. The “CharacterFactory” class is responsible for instantiating these character classes based on the user’s choice. The client code (game or player) interacts with the factory, requesting specific character types, and receives instances of the characters without being aware of the underlying implementation details. This design promotes flexibility, scalability, and the easy addition of new character types to the game without modifying the core client code.

Step-by-step implementation of the Factory design pattern

Step 1- Create an interface

First, we create a Character interface, representing the common attributes and methods that all Clash of Clans characters should implement. It has two methods: selectCharacter(), which displays the selected character, and usePower(), which activates the character’s unique power.

Java
public interface Character {
    void selectCharacter();
    void usePower();
}

Step 2- Create concrete character classes

We create three concrete classes: Barbarian, Archer, and wizard, which implement the Character interface with their original powers. Each class overrides the usePower() method to describe the character’s special ability.

Let’s implement the Barbarian class first:

Java
public class Barbarian implements Character {

	@Override
	public void selectCharacter() {
		System.out.println("Selected character: Barbarian");
	}

	@Override
	public void usePower() {
		System.out.println("Power: Rapid attack with double damage!");
	}

}

Below is the code for the Archer class.

Java
public class Archer implements Character {

	@Override
	public void selectCharacter() {
		System.out.println("Selected character: Archer");	
	}

	@Override
	public void usePower() {
		 System.out.println("Power: Deploy multiple arrows for area damage!");
	}

}

Similarly, we have an implementation for the Wizard class.

Java
public class Wizard implements Character {

	@Override
	public void selectCharacter() {
		System.out.println("Selected character: Wizard");
	}

	@Override
	public void usePower() {
		System.out.println("Power: Cast a fireball that deals splash damage!");
	}

}

Step 3- Create CharacterFactory class

The CharacterFactory class remains unchanged, responsible for creating instances of the Clash of Clans characters based on the user’s input.

Java
public class CharacterFactory {
	public Character createCharacter(String characterType) {
        switch (characterType) {
            case "Barbarian":
                return new Barbarian();
            case "Archer":
                return new Archer();
            case "Wizard":
                return new Wizard();
            default:
                throw new IllegalArgumentException("Invalid character type: " + characterType);
        }
    }
}

Step 4- Client Code

In the ClashOfClans class (representing the client code), which interacts with the CharacterFactory to create the characters, their powers are displayed using the usePower() method. The client code interacts with the Characters without needing to know the specifics of their power implementations.

Java
public class ClashOfClans {
	public static void main(String[] args) {
        CharacterFactory characterFactory = new CharacterFactory();

        // Character creation using the factory without knowing the concrete classes.
        Character barbarian = characterFactory.createCharacter("Barbarian");
        Character archer = characterFactory.createCharacter("Archer");
        Character wizard = characterFactory.createCharacter("Wizard");

        // Interact with the characters and use their powers.
        barbarian.selectCharacter();
        barbarian.usePower();

        archer.selectCharacter();
        archer.usePower();

        wizard.selectCharacter();
        wizard.usePower();
    }
}

Step 5- Test Application

Now, when you run the ClashOfClans program, it will display the selected character and the unique power of each character type, reflecting the original powers from the game.

Factory design pattern
Fig 2- Output : Factory design pattern

Advantages of Factory design pattern

  • Encapsulation of Object Creation
    • The Factory Design Pattern encapsulates the object creation process within the factory classes, hiding the complexities from the client code. This promotes a cleaner and more organized codebase.
  • Decoupling Client Code
    • Client code doesn’t need to know the specific classes it needs to instantiate. It interacts with the factory interface, allowing for flexibility and reducing dependencies.
  • Improved Code Maintenance
    • When adding new product types, you only need to modify the factory, not the client code. This makes it easier to extend and maintain the system.
  • Centralized Control
    • The Factory Pattern centralizes the creation logic in one place, making it easier to manage and modify the object creation process.
  • Dependency Injection
    • The Factory Pattern facilitates dependency injection, enabling better unit testing and inversion of control.
  • Polymorphic Object Creation
    • The factory can return objects of different concrete types that share a common interface, promoting polymorphism and code reuse.

Disadvantages of Factory design pattern

  • Increased Complexity
    • Introducing a factory can add some complexity to the codebase, especially for simple object creation scenarios.
  • Additional Abstraction
    • The Factory Design Pattern may introduce additional abstraction, making it harder to understand for some developers.
  • Code Duplication
    • If not carefully designed, factory methods may duplicate code across different product types.
  • Runtime Overhead
    • The factory introduces a runtime overhead as an additional layer of abstraction, which may have a minor impact on performance.
  • Potential Overuse
    • Using the Factory Pattern for simple object creation scenarios can lead to over-engineering and unnecessary complexity.
  • Tighter Coupling with Factory
    • The client code becomes tightly coupled with the factory implementation, reducing flexibility if you need to switch to a different object creation mechanism.

Leave a Reply

Your email address will not be published. Required fields are marked *