In this article, we’ll be discussing Creational Design Pattern i.e what are the types of Creational Design Pattern with examples
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; } }
Application of Singleton pattern can also be seen in Logging, caching, etc.
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.
There are a few issues while using Singleton and Factory pattern:
Here comes the builder pattern to make our life easy.
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.
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
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.
This post was last modified on January 24, 2022