Factory Design Pattern

What is a Factory Design Pattern

Factory design pattern is used when we have a super class with multiple sub-classes and based on input, we need to return one of the sub-classes.

This pattern takes out the responsibility of instantiation of a class from client program to the factory class. We can apply Singleton pattern on Factory class or make the factory method static.

Super class in factory pattern can be an interface or a normal java class.

Explanation

The Factory design pattern is a way of creating objects in an object-oriented programming language.

Imagine you have a car factory. The factory makes cars. When you order a car, you specify the type of car you want (e.g. sedan, SUV, sports car, etc.). The factory then builds the car for you and delivers it to you.

Similarly, in the Factory design pattern, you have a factory class that creates objects of different types. When you ask the factory to create an object, you specify the type of object you want. The factory then creates the object for you and returns it to you.

This allows you to separate the process of creating objects from the rest of your code, making it easier to change the way objects are created if needed.

Think of the factory as a kind of “object-making machine.” Instead of writing code to create objects, you tell the factory what you want, and it creates the objects for you. This makes your code easier to read and maintain, and makes it easier to change how objects are created if needed.


The Factory design pattern is often used in situations where client code cannot anticipate the type of objects it needs to create.

The Factory design pattern provides several benefits:

Abstraction: It separates the implementation details of object creation from the client code, allowing the client code to focus on the task at hand and not the details of object creation.

Flexibility: The Factory design pattern allows you to add new types of objects to your application without having to modify the client code. This makes it easier to maintain and extend your application.

Reusability: By encapsulating the details of object creation in a factory class, you can reuse the factory in multiple parts of your application, making your code more modular and easier to maintain. Overall, the Factory

Benefits

  • Factory pattern provides approach to code for interface rather than implementation.
  • Factory pattern removes the instantiation of actual implementation classes from client
    code
    , making it more robust, less coupled and easy to extend.
  • Factory pattern provides abstraction between implementation and client classes through inheritance.

Examples

  • java.util.Calendar, ResourceBundle, java.text.DateFormat and java.text.NumberFormat getInstance () methods uses Factory pattern.
  • valueOf () method in wrapper classes like Boolean, Integer etc.

the Calendar class utilizes the Factory Method getInstance() to create instances of the Calendar class based on the user’s default locale and timezone. The getInstance() method is static, and it internally determines which specific implementation of Calendar to return based on the locale and timezone settings.

// Get an instance of the default Gregorian calendar
Calendar gregorianCalendar = Calendar.getInstance();
System.out.println("Default Calendar: " + gregorianCalendar.getClass().getName());

// Get an instance of a different calendar system (e.g., Buddhist)
Calendar buddhistCalendar = Calendar.getInstance(java.util.Locale.forLanguageTag("th-TH"));
System.out.println("Buddhist Calendar: " + buddhistCalendar.getClass().getName());

Implementation

It allows the client code to create objects by delegating the responsibility of object instantiation to a factory class.

package com.rndayala.designpatterns.factory;

// interface that defines common functionality to be 
// implemented by all related types
public interface Shape {
	void draw();
}

// Concrete class that implements the functionality provided by interface
public class Circle implements Shape {
	@Override
	public void draw() {
		System.out.println("Inside Circle::draw() method."); 

	}
}

// Concrete Product classes implementing the Shape interface
public class Rectangle implements Shape {
	@Override
	public void draw() {
		System.out.println("Inside Rectangle::draw() method."); 
	}
}

// Concrete Product classes implementing the Shape interface
public class Square implements Shape {
	@Override
	public void draw() {
		System.out.println("Inside Square::draw() method."); 

	}
}

Then you define a Factory class that does the instantiation of object based on the type.

package com.rndayala.designpatterns.factory;

// Simple Factory class responsible for creating Shape objects
public class FactoryClass {
	
	// static Factory method which instantiates the object and returns to client 
	public static Shape getShape(String shapeType) {
		if (shapeType == null) {
			return null;
		}

		if (shapeType.equalsIgnoreCase("CIRCLE")) {
			return new Circle();
		} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
			return new Rectangle();
		} else if (shapeType.equalsIgnoreCase("SQUARE")) {
			return new Square();
		} else if (shapeType.equalsIgnoreCase("TRIANGLE")) {
			// TODO : Add Triangle class which implements Shape interface
		}
		return null;
	}
}

Client code that uses the Factory class :

package com.rndayala.designpatterns.factory;

public class FactoryTest {

	public static void main(String[] args) {
		// create objects of  the Shape interface by calling the getShape method 
		// and passing the appropriate String argument. 
		// Type of object to create is determined at runtime by user.
		// NOTE - We code against interface. Higher level modules doesn't depend on lower level classes. 
		Shape shape = FactoryClass.getShape("Circle");
		shape.draw();
		
		shape = FactoryClass.getShape("Square");
		shape.draw();
		
		shape = FactoryClass.getShape("Rectangle");
		shape.draw();
	}
}

Implementations of the Factory Design Pattern in Java provide a way to encapsulate object creation, allowing the client code to focus on using the objects rather than being concerned with how they are created.


Simple Factory Method

In the simple factory method, a separate factory class is responsible for creating instances of various concrete classes that share a common superclass or interface.

// Interface for the Product objects
interface Product {
    void doSomething();
}

// Concrete Product classes implementing the Product interface
class ConcreteProductA implements Product {
    public void doSomething() {
        System.out.println("Doing something in ConcreteProductA.");
    }
}

class ConcreteProductB implements Product {
    public void doSomething() {
        System.out.println("Doing something in ConcreteProductB.");
    }
}

// Simple Factory class responsible for creating Product objects
class ProductFactory {

    // static factory method
    public static Product createProduct(String type) {
        switch (type) {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new IllegalArgumentException("Invalid product type: " + type);
        }
    }
}

// Client code
public class Main {
    public static void main(String[] args) {
        Product productA = ProductFactory.createProduct("A");
        productA.doSomething(); // Output: Doing something in ConcreteProductA.

        Product productB = ProductFactory.createProduct("B");
        productB.doSomething(); // Output: Doing something in ConcreteProductB.
    }
}

Implementations of the Factory Design Pattern in Java provide a way to encapsulate object creation, allowing the client code to focus on using the objects rather than being concerned with how they are created.


Use cases

Some common use cases of the Factory Pattern include:

  • When a class cannot anticipate the type of objects it needs to create
  • When a class wants its subclasses to specify the objects it creates
  • When classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

Examples of situations where the Factory Pattern can be used include:

  • when creating objects for UI elements, such as buttons or panels, based on user input or configuration data
  • when implementing a plugin architecture where objects of different types can be created based on user-selected options
  • when managing the creation of objects that are part of a larger system, such as creating database connections based on configuration data.

Leave a comment