Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
The Factory Design Pattern is one of the most widely used design patterns in Java, particularly in scenarios where object creation is complex or requires flexibility. It falls under the category of Creational Design Patterns, which deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.
In this blog, we will study Factory Design Pattern in Java. We will also discuss some programming code for better understanding.
What is a Design Pattern?
In object-oriented programming, a design pattern is a reusable solution to a common problem in software design. Rather than providing finished code, design patterns offer templates for solving recurring issues in a flexible and maintainable way. These patterns are based on best practices that have evolved over time through real-world use.
Design patterns help improve code readability, reusability, and scalability, making them essential tools for building robust software.
There are three main types of design patterns:
Creational – deal with object creation
Structural – focus on class and object composition
Behavioral – manage communication between objects
Creational patterns, such as the Factory Pattern, aim to make object creation more dynamic and flexible without exposing the instantiation logic.
What is the Factory Design Pattern in Java?
Factory Design Pattern in Java is an example of a creational pattern. The creational patterns are used to create objects. The factory patterns are used when defining an interface or abstract class with multiple subclasses for an object. Based on the input, the factory design pattern returns one of these subclasses. It is useful when we need many objects of similar types, but we don't want to specify the type of object at the time of creation.
Before discussing the implementation of factory design patterns, first, we need to understand what are inheritance, abstract classes, and interfaces to have a clear picture of what factory design patterns are.
Inheritance: allows one class to obtain all the properties of a parent class. It is one of the critical concepts of Object Oriented Programming (OOP). Java does not support multiple inheritances in classes, i.e., a child class cannot acquire the properties and behaviors of more than one superclass. So, interfaces were introduced.
Interface: is the template of a class. Interfaces are similar to classes in Java, but the only difference is that a class can implement more than one interface in Java. It contains functions that a class can implement.
Abstract classes: are classes that may or may not include abstract methods. We cannot instantiate an abstract class (objects of abstract classes cannot be created).
Example of Factory Method Design Pattern in Java
Suppose we are building an application where different types of vehicles are needed, and we want to create them dynamically based on user input. We will use the Factory Method Design Pattern to achieve this.
Step 1: Create an interface for the Product (Vehicle).
// Vehicle.java
public interface Vehicle {
void drive();
}
Step 2: Create Concrete Products (Car, Bike, Truck).
// Car.java
public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("Driving a Car");
}
}
// Bike.java
public class Bike implements Vehicle {
@Override
public void drive() {
System.out.println("Riding a Bike");
}
}
// Truck.java
public class Truck implements Vehicle {
@Override
public void drive() {
System.out.println("Driving a Truck");
}
}
Step 3: Create an abstract class that declares the Factory Method.
// VehicleFactory.java
public abstract class VehicleFactory {
// Factory Method to be implemented by subclasses
public abstract Vehicle createVehicle();
}
Step 4: Create Concrete Factories for each Vehicle type.
// CarFactory.java
public class CarFactory extends VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Car(); // Creates a Car object
}
}
// BikeFactory.java
public class BikeFactory extends VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Bike(); // Creates a Bike object
}
}
// TruckFactory.java
public class TruckFactory extends VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Truck(); // Creates a Truck object
}
}
Step 5: Use the Factory Method in the Client Code.
public class Main {
public static void main(String[] args) {
// Create a Car using CarFactory
VehicleFactory vehicleFactory = new CarFactory();
Vehicle vehicle1 = vehicleFactory.createVehicle();
vehicle1.drive(); // Output: Driving a Car
// Create a Bike using BikeFactory
vehicleFactory = new BikeFactory();
Vehicle vehicle2 = vehicleFactory.createVehicle();
vehicle2.drive(); // Output: Riding a Bike
// Create a Truck using TruckFactory
vehicleFactory = new TruckFactory();
Vehicle vehicle3 = vehicleFactory.createVehicle();
vehicle3.drive(); // Output: Driving a Truck
}
}
Explanation
Vehicle (Product Interface): This is the interface that declares the drive() method, which all vehicles must implement.
Car, Bike, Truck (Concrete Products): These classes implement the Vehicle interface and provide specific implementations for the drive() method.
VehicleFactory (Abstract Factory Class): This abstract class declares the factory method createVehicle() which will be overridden by its subclasses to create specific types of vehicles.
CarFactory, BikeFactory, TruckFactory (Concrete Factories): These are the classes that extend the VehicleFactory and implement the createVehicle() method to return instances of Car, Bike, and Truck respectively.
Client (Main Class): In this class, we create concrete factory instances (like CarFactory, BikeFactory, etc.) and use them to create specific vehicles dynamically.
Implementations of Factory Method Design Pattern
Let us now learn the implementation of the factory design pattern.
Factory Design Pattern Super Class
In Factory Design pattern, a super class provides a skeleton for the subclasses to be created. It allows the subclass to extend itself and change the type of object to be returned. It acts as an interface for object creation. It can either be a normal class, an abstract class or an interface.
Suppose we want to create a program to calculate the movie ticket bill. Firstly, we will create an abstract class called Ticket (super class).
import java.io.*;
abstract class Ticket {
protected double Price;
abstract void getPrice();
public void calculateBill(int units) {
System.out.println(units*Price);
}
}
You can also try this code with Online Java Compiler
The class that extend or implement the super class in factory design pattern are known as sub class. These classes are the interface to return different types of object based on need. They override the super class's methods to have their own implementation
Now, we will create sub classes that extend the Ticket abstract class.
class LowerSeat extends Ticket {
public void getPrice() {
Price = 225;
}
}
class MiddleSeat extends Ticket {
public void getPrice() {
Price = 275;
}
}
class BalconySeat extends Ticket {
public void getPrice() {
Price = 325;
}
}
You can also try this code with Online Java Compiler
Lastly, we will generate the bill using GetTicketFactory to get the object of classes by passing information such as the type of tickets LowerSeat or MiddleSeat, or BalconySeat.
class GenerateBill {
public static void main(String args[])throws IOException {
GetTicketFactory TicketFactory = new GetTicketFactory();
System.out.print("Enter the type of tickets for which the bill will be generated: ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String TicketType = br.readLine();
System.out.print("Enter the number of tickets for bill will be calculated: ");
int units = Integer.parseInt(br.readLine());
Ticket p = TicketFactory.getTicket(TicketType);
System.out.print("Bill amount for "+TicketType+" of "+units+" tickets is: ");
p.getPrice();
p.calculateBill(units);
}
}
You can also try this code with Online Java Compiler
The first image shows the Bill amount for the first input as LowerSeat, and the number of tickets is 5, and the second input as BalconySeat, and the number of tickets is 4.
The second image shows an error as the MidSeat was not defined in the program. Instead, it was MiddleSeat.
In the code above, the client code doesn't need to know the details of object creation. The client only needs to know the interface of the Ticket class, GenerateBill, and GetTicketFactory class. The Factory pattern abstracts the object creation process, making it easy to change the type of object created without affecting the client code.
Factory Method vs Abstract Factory Pattern
The Factory Method Pattern provides an interface for creating a single object, allowing subclasses to decide which class to instantiate. The Abstract Factory Pattern, on the other hand, provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Both are creational design patterns in Java, but they solve problems at different levels of object creation and flexibility.
Comparison Table: Factory Method vs Abstract Factory
Feature
Factory Method Pattern
Abstract Factory Pattern
Purpose
Creates one specific object
Creates related objects (product families)
Object Creation
Focused on a single product
Works with multiple related products
Complexity
Less complex and easier to implement
More complex due to multiple factories
Use Case
Use for one object with varying implementations
Use when objects must work together cohesively
Example
Logger factory for FileLogger or DBLogger
GUI factory for Windows or Mac UI components
Structure
Subclass decides what to instantiate
Central factory provides multiple product objects
Which One to Use When?
Use Factory Method when you need to create a single object but want the instantiation logic to be handled by subclasses. Example: Choosing between FileLogger or ConsoleLogger based on configuration.
Use Abstract Factory when you need to create a set of related objects that should work together. Example: Creating a UIFactory that builds consistent buttons, menus, and toolbars for Windows or Mac.
Rule of Thumb: Use Factory Method for one-off object creation, and Abstract Factory when multiple objects need to be created together in a consistent group.
These patterns help enforce consistency, reduce coupling, and enhance code flexibility in large-scale Java applications. Use them wisely based on your application's design needs.
Components of Factory Design Pattern
The Factory Design Pattern comprises the following components:
Product: An interface or abstract class defining the operations that concrete products must implement.
Concrete Product: The actual implementation of the Product interface, representing different objects the factory can create.
Creator (Factory): An abstract class or interface declaring the factory method for creating Product objects, along with core business logic.
Concrete Creator: Subclasses of the Creator that override the factory method to instantiate specific Concrete Products.
Client: The code that uses the factory and product interfaces, without knowing the specific classes of the created objects.
Advantages of Factory Design Pattern
Now, let's talk about the advantages of factory design patterns in Java:
The client code only needs to know the interface of the factory class, and it doesn't need to know how the object was created. So it decouples the client from the creation process.
We can change the object creation process by changing the factory class and not disturbing the client code. This makes the code more maintainable.
As the client only knows the interface of the factory class instead of the creation process, this makes the code more readable.
Disadvantages of Factory Design Pattern
Introducing a factory adds an extra layer of abstraction, which can make the code more complex and harder to understand, especially for simple object creation.
If new types of products need to be added frequently, the factory code must be updated accordingly, leading to higher maintenance effort.
In some cases, if the factory method logic is not well-designed, it can be difficult to extend or modify the product creation process without affecting existing code.
The factory class might accumulate too many responsibilities, such as creating different types of objects, which can violate the Single Responsibility Principle.
Although the factory decouples the client from specific classes, the client still depends on the factory, which could be a single point of failure if not designed carefully.
Frequently Asked Questions
What is the Factory Pattern design principle?
The Factory Pattern follows the principle of "encapsulating object creation," promoting loose coupling by delegating the instantiation process to subclasses.
Why is the factory pattern used?
The Factory Pattern is used to create objects without specifying the exact class, allowing for flexibility and scalability in code while adhering to the Open/Closed Principle.
What is the best example of factory design pattern?
The best example for understanding Factory Design Pattern is the above example in this blog which used an abstract class called Ticket and 3 sub-classes for each type of ticket possible. Then we created a factory class GetTicketFactory which returned the appropriate object depending on the type of ticket to be booked.
What is the purpose of factory method design pattern?
Factory method design pattern allows the subclasses to override the super class's methods and return the appropriate object type. It does not put the responsibility on the application to create the correct object type, it instead puts the responsibility on the Factory Class to create the appropriate object type and return to the application.
What is the factory design pattern in MVC?
Factory design pattern in MVC is used to create objects of a super class by taking away the responsibility from the application and giving it to the Factory Class to determine which object type is appropriate for each request.
Conclusion
We expect this article was insightful and that you learned something new today. In this blog, we learned about factory design patterns in Java. It is used in the case where there are multiple subclasses of a parent class. Depending on the input, we return one of these subclasses. We also discussed its implementation, advantages, and some examples in Java for clarity. If you want to learn more about design patterns, do visit.