Creational Design Patterns In Java With Example

What are Design Patterns?

  • Industry standard approach to solve a recurring problem
  • This leads to readability, highly maintainable code
  • Major adv is new developers can easily read code, as these patterns are popular

Types of Design Patterns in Java

  • Creational Design pattern – Provides best possible approaches of creating objects
  • Structural Design pattern – Combining classes to form the best possible Structure
  • Behavioural Design pattern – how data should interact with each other

In this article, we’ll be discussing Creational Design Pattern i.e what are the types of Creational Design Pattern with examples

Creational Design Patterns In Java

1. Singleton Design Pattern

  • Ensures that only 1 instance of the class exists in Memory
  • There should be one application-wide gate for creating the object

Steps to implement:

  1. Add a private constructor
  2. Add a private static variable of the class
  3. Add a public static method to get the instance of this class

The first example is a way of eager implementation of Singleton pattern, by eager we mean that we have a final instance of a class that gets created in the memory as soon as the class loads in JVM, the drawback is object always gets created and the user has less control

The second example of lazy initialization is in which the object only gets created when the user actually wants the object.

Singleton Design Pattern code example:

public class SingletonEager {

   public static final SingletonEager instance = new SingletonEager();


   private SingletonEager() {

   }


   public static SingletonEager getInstance() {

       return instance;

   }

}


class SingletonLazy {

   public static SingletonLazy instance = null;

   private SingletonLazy() {

   }


   public static SingletonLazy getInstance() {

       if (instance == null) return new SingletonLazy();

       return instance;

   }

}

Examples of Singleton Desing pattern in JDK:

  • java.lang.Runtime
  • java.lang.System

Application of Singleton pattern can also be seen in Logging, caching, etc.

2. Factory Design Pattern

This pattern is used when we have a parent class and this parent class has multiple sub-classes, whenever some input comes we need to return the object of one of the sub-classes.
The whole idea is to ease the work on calling code by handling the responsibility of object creating to the factory class.

Factory Design Pattern code example:

public class AnimalFactory {
   private AnimalFactory() {
   }
   public static Animal getAnimal(AnimalType type) {
       switch (type) {
           case CAT: return new Cat();
           case DOG: return new Dog();
           case COW: return new Cow();
           default: throw new RuntimeException("Invalid Animal Type");
       }
   }
}

interface Animal {
   String getName();
}

enum AnimalType { DOG, CAT, COW }

class Dog implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

class Cat implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

class Cow implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

As we can clearly see that the whole job of deciding which object to create is handled by the factory class, thus the calling code only needs to pass the type of Animal to get the desired object.

The major advantage of the Factory pattern is that adding new sub-classes becomes really easy and we need to change the implementation code.

Examples of Factory Desing pattern in JDK:

  • java.util.Calendar
  • java.lang.Class

3. Builder Design Pattern

There are a few issues while using Singleton and Factory pattern:

  • If the class has a large number of properties you can imagine how large the constructor would be.
  • If we are passing so many variables there may be some null data which leads to error.
  • Also, the calling code needs to remember the order of parameters in the constructor.

Here comes the builder pattern to make our life easy.

Steps to Implement:

  1. Add getter methods to the class
  2. Add a private constructor which takes the builder object
  3. Add a static inner class of builder type
  4. In the inner class, the mandatory objects should an instantiated via the constructor and optional variables via a setter method.
  5. The return type of setter methods should be of Builder type
  6. Add a build method on the inner class which return the Outer class object

Builder Design Pattern code example:

public class House {
   private String location;
   private String area;
   private String floorType;

   // optional fields
   private boolean hasSwimmingPool;
   private boolean hasGarage;

   private House(HouseBuilder builder) {
       this.location = builder.location;
       this.area = builder.area;
       this.floorType = builder.floorType;

       this.hasSwimmingPool = builder.hasSwimmingPool;
       this.hasGarage = builder.hasGarage;
   }

   public String getLocation() { return location; }
   public String getArea() { return area; }
   public String getFloorType() { return floorType; }
   public boolean isHasSwimmingPool() { return hasSwimmingPool; }
   public boolean isHasGarage() { return hasGarage; }

   public static class HouseBuilder {
       private String location;
       private String area;
       private String floorType;

       // optional fields
       private boolean hasSwimmingPool;
       private boolean hasGarage;

       public HouseBuilder(String location, String area, String floorType) {
           this.location = location;
           this.area = area;
           this.floorType = floorType;
       }
       public HouseBuilder setHasSwimmingPool(boolean hasSwimmingPool) {
           this.hasSwimmingPool = hasSwimmingPool;
           return this;
       }

       public HouseBuilder setHasGarage(boolean hasGarage) {
           this.hasGarage = hasGarage;
           return this;
       }

       public House build() {
           return new House(this);
       }
   }
}
class Main {
   public static void main(String[] args) {
       // set only mandatory fields
       House delhiHouse = new House.HouseBuilder("Delhi", "500 sq ft", "wooden").build();

       // set optional fields too
       House chicagoHouse = new House.HouseBuilder("Chicago", "200 sq ft", "marble")
               .setHasGarage(true)
               .setHasSwimmingPool(false).build();
   }
}

As we can see that object creation becomes so much easier, by chaining of methods, the caller code has complete control with so much ease, this becmoes a lot helpful when a class has a huge number of properties.

Examples of Factory Desing pattern in JDK:

  • java.lang.StringBuilder
  • java.util.steram.Stream.Builder

4. Prototype Design Pattern

Used when object creation is complex and requires a lot of resources in terms on time, CPU etc.
This provides a way of copying the original object into a new object and then do the needed modification

Copying is done by using cloning of object.

Prototype Design Pattern code example:

public class Employee {
   private final String name;
   private final Long id;

   public Employee(String name, Long id) {
       this.name = name;
       this.id = id;
   }
}

class EmployeeDAO implements Cloneable {
   private static final List<Employee> employees;

   static {
       employees = new ArrayList<>();
       Employee e1 = new Employee("Ramu", 100L);
       Employee e2 = new Employee("Raju", 101L);
       employees.add(e1);
       employees.add(e2);
   }

   public static List<Employee> getEmployees() { return employees; }

   @Override
   public List<Employee> clone() throws CloneNotSupportedException {
       List<Employee> dummyEmployees = new ArrayList<>();
       for (Employee employee: employees) {
           dummyEmployees.add(employee);
       }
       return dummyEmployees;
   }
}

class Main {
   public static void main(String[] args) throws CloneNotSupportedException {
       EmployeeDAO employeeDAO = new EmployeeDAO();
       List<Employee> originalEmployees = employeeDAO.getEmployees();
       List<Employee> updatedEmployees = employeeDAO.clone();
       // perform modifications on the updated List
   }
}

One of the real life applications of this can be seen in caching, where to prevent repetitive DB calls we cache the data, similalry rather tha calling EmlpoyeeDAO again and again we can clone its objects and re-use accordingly.

Example in JDK: Object cloning

5. Abstract Factory Design Pattern

This is very much similar to the Factory Pattern. It can be seen as a Factory of Factories
Provides an extra layer of abstraction over the factory pattern

The shortcome of factory pattern is there is only 1 factory class, if object creation of sub-classes becomes more and more complex then the factory class also becomes more complex.

Abstract Factory class says we can have multiple factores there by each factory responsible for creating its own type of class object.

Abstract Design Pattern code example:

class Main {
   public static void main(String[] args) {
       Animal dog = AbstractAnimalFactory.getAnimal(new DogFactory());
       Animal cow = AbstractAnimalFactory.getAnimal(new CowFactory());
   }
}

public interface AbstractAnimalFactory {
   public abstract Animal createAnimal();

   public static Animal getAnimal(AbstractAnimalFactory abstractAnimalFactory) {
       return abstractAnimalFactory.createAnimal();
   }
}

class DogFactory implements AbstractAnimalFactory {
   @Override
   public Animal createAnimal() {
       return new Dog();
   }
}

class CatFactory implements AbstractAnimalFactory {
   @Override
   public Animal createAnimal() {
       return new Cat();
   }
}

class CowFactory implements AbstractAnimalFactory {
   @Override
   public Animal createAnimal() {
       return new Cow();
   }
}

interface Animal {
   String getName();
}

class Dog implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

class Cat implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

class Cow implements Animal {
   @Override
   public String getName() { return "COOL NAME"; }
}

This article is contributed by Shiva Tiwari.

Leave a Reply