Factory Design Pattern

Design Pattern Tutorial Series

Factory Design Pattern in Java - 5-Step Guide

As arguably the most popular creational design pattern, the factory pattern provides guidelines for how to flexibly and conveniently create different objects with the same method, by only changing the method’s argument. Utilizing the factory pattern in the creation of objects allows all complexities of the creation to be hidden away. Simultaneously the factory can be designed to create any variation of an object, as long as all objects extend from the same super-class.

Table of Contents

INTEGU - Factory-Design-Pattern-Overview

Step 1 - The Objective

To give a better understanding of how the factory pattern works, we will take the example of a car rental service. In this case, the car rental service has two types of customers. Those with a company contract and those without. For each customer type, the rental service has two variations of cars, grade A and grade B.

The owner of the rental service wants a system, which takes in a customer’s requested grade and contract type and outputs the correct car. Additionally, the car should also be checked by a mechanic, cleaned up, and fully fueled.

In other words, this means, that we need a way of creating different variations of a car, which needs to undergo multiple procedural steps before being handed over to the customers.

As a start, let’s try and see how this could be solved without the factory pattern.

INTEGU - Objective- Factory Design Pattern

Step 2 - Open Creation

As a beginning, we start by checking whether our customer has a company contract. If so, we retrieve their requested grade of car and runs through the options to see if we have a match.

For this scenario, we have already a Car super-class, which can be extended by all car brands sub-classes (Tesla, Audi, Volkswagen, and Toyota). This allows us to utilize the common methods of the Car super-class to perform a mechanical service check, clean up the car, and put fuel on it.

All of the above mentioned steps have all be accomplished inside the main-method of our system, as can be seen from the code sample below.

Although this code sample solves the objective, it has multiple problems. Firstly, it is not desirable to have all the car selection and preparation logics at the same level of abstraction as where the customer is. We want that kind of logic hidden away from the customer so that they only see the ready and shiny car. In code practice we also want this logic hidden away in its own class, to avoid modifications, while working on other parts of the main-method.

Secondly, we also want each contract type to be handled individually. Let’s say that the rental service one day shut down their company contract agreement. In this case, we want to easily be able to remove the logics related to the company contracts, without jeopardizing changes anywhere else in the system.

With these issues in mind, let’s see what the factory pattern can do for us.

INTEGU - Problem-Theory- Factory Design Pattern
public static void main(String[] args) {
        Customer customerOne = new Customer("B", true);
        if(customerOne.hasCompanyContract()){
            switch (customerOne.getGradeRequest()){
                case "A":
                    carOne = new Tesla();
                    break;
                case "B":
                    carOne = new Audi();
                    break;
                default:
                    System.out.println("The requested car was unfortunately not available.");
                    carOne = null;
            }
        }else {
            switch (customerOne.getGradeRequest()) {
                case "A":
                    carOne = new Volkswagen();
                    break;
                case "B":
                    carOne = new Toyota();
                    break;
                default:
                    System.out.println("The requested car was unfortunately not available.");
                    carOne = null;
            }
        }
        carOne.clean();
        carOne.mechanicCheck();
        carOne.fuelCar();
        carOne.startEngine();
    }

Step 3 - Concept Of The Factory Pattern

The core concept of the factory pattern is to make a class (the factory), which defines the rules of how to create a specific type of object (the product). The pattern can always be recognized by the create-method.

Imagine that we took all the logic from the rental service’s car selection and put it into two separate factory-classes. Both classes would be factories, but one would be related to customers with company contracts, while the other would be related to those without. Individually, these factory-classes are able to figure out what car a customer want. However, they are also aware of the common procedure, which need to take place before the customers get their car. This is because, all the common procedures have been put into the factory-super-class, which both of the car selection factories extend.

Separating the logics in the appropriate level of abstraction, makes the code much easier to read, scale, and maintain.

INTEGU - Solution-theory-code- Factory Design Pattern

Step 4 - Class Diagram (UML)

As can be interpreted from the previous sections, we already know a lot about our class structure. As a start, we know that our products are cars and that our factories are the logic and procedures required for providing a car.

As mentioned previously, all car classes (Audi, Tesla, Volkswagen, and Toyota) extend the Car super-class, and both car selection logics (with- /without company contract) extend the Factory super-class.

The Factory super-class contains the create-method, which is close to obligatory for any factory pattern. Within this method the initial step is to retrieve the requested car. However, since the super-class does not know anything about the selection logic, it simply states the retrieveCar-method as abstract. Thereby it requires any class, which extends it, must override the retrieveCar-method and implement its own selection logic.

After having retrieved the car, we come back to the create-method. The remaining part of the method then goes into preparation procedures. This procedure is the same for all cars and we can, therefore, state the steps within the factory super-class.

The Factory super-class does at no point know which specific car (product) it is creating. However, it can rely on the car to have the required methods, since all variations of car classes extend the Car super-class.

INTEGU - Class-Diagram-Frame Factory design pattern

Step 5 - Code (Java)

Given that code is sometimes difficult to learn through concepts and theory, I provide the code for the example in both video and blog form.

Hopefully, this will be sufficient for you to learn to identify and implement the factory pattern in your future endeavors as a software developer.

The Factory (Logics And Procedure)

public abstract class Factory {
    public Car create(String requestedGrade) {
        Car car = retrieveCar(requestedGrade);
        car = prepareCar(car);
        return car;
    }
    private Car prepareCar(Car car){
        car.clean();
        car.mechanicCheck();
        car.fuelCar();
        return car;
    }
    abstract Car retrieveCar(String requestedGrade);
}
public class CompanyCarFactory extends Factory {
    @Override
    Car retrieveCar(String requestedGrade) {
        switch (requestedGrade) {
            case "A":
                return new Tesla();
            case "B":
                return new Audi();
            default:
                System.out.println("The requested car was unfortunately not available.");
                return null;
        }
    }
}

The Products (Cars)

public abstract class Car {
    public int horsePower;
    public String fuelSource;
    public String color;
    public void startEngine(){
        System.out.println("The " + fuelSource + " engine has been started, and is ready to utilize " + horsePower + " horsepowers.n" );
    }
    public void clean(){
        System.out.println("Car has been cleaned, and the " + color.toLowerCase() + " color shines");
    }
    public void mechanicCheck(){
        System.out.println("Car has been checked by the mechanic. Everything looks good!");
    }
    public void fuelCar(){
        System.out.println("Car is being filled with " + fuelSource.toLowerCase());
    }
}
public class Audi extends Car {
    public Audi() {
        horsePower = 250;
        color = "Black";
        fuelSource = "Diesel";
    }
}

How To Use The Factory Pattern

public static void main(String[] args) {
        Customer customerOne = new Customer("B", true);
        Factory factory = getCarFactory(customerOne);
        Car carOne = factory.create(customerOne.getGradeRequest());
        carOne.startEngine();
    }
private static Factory getCarFactory(Customer customer) {
        if(customer.hasCompanyContract()){
            return new CompanyCarFactory();
        }else{
            return new CarFactory();
        }
    }
public class Customer {
    private String gradeRequest;
    private boolean hasCompanyContract;
    public Customer(String gradeRequest, boolean hasCompanyContract) {
        this.gradeRequest= gradeRequest;
        this.hasCompanyContract = hasCompanyContract;
    }
    public boolean hasCompanyContract() {
        return hasCompanyContract;
    }
    public String getGradeRequest() {
        return gradeRequest;
    }
}

Recommended Reading

Article

  • Theoretical walkthrough – Source Making – Blog
  • Practical walkthrough – Tutorialspoint – Blog
  • Practical walkthrough – Springframework Guru – Blog

Tools

    • Camtasia – Used for illustrations and video – Camtasia

Books

Video Tutorial 

  • Theoretical  (based on “Head-First: Design Patterns”) – Christopher Okhravi – YouTube
  • Practical – Derek Banas – YouTube

About

Hi, I'm the Author

My name is Daniel H. Jacobsen and I’m a dedicated and highly motivated software developer with a masters engineering degree within the field of ICT. 

I have through many years of constantly learning and adapting to new challenges, gained a well-rounded understanding of what it takes to stay up to date with new technologies, tools and utilities. 

The purpose of this blog is to share both my learnings and knowledge with other likeminded developers as well as illustrating how these topics can be taught in a different and alternative manner.

If you like the idea of that, I would encourage you to sign up for the newsletter.

Cheers! 🍺

Didn't Find What You Were Looking For?

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages
Scroll to Top