Creational Design Patterns:

Saurav Kumar
4 min readNov 22, 2023

--

Creational design patterns focus on how objects are created, instantiated, and managed. They provide mechanisms for controlling the object creation process to ensure flexibility, efficiency, and reusability. There are five commonly recognized creational design patterns:

1. Singleton Pattern:

  • Purpose: Ensures that a class has only one instance and provides a global point of access to that instance.
  • Use Cases: When you want to ensure a single point of control or coordination (e.g., a configuration manager, or a database connection pool).
  • Implementation: Typically involves a private constructor, a static method to access the instance, and a private static variable to hold the unique instance.
public class Singleton {
private static Singleton instance;

private Singleton() {
// Private constructor to prevent external instantiation.
}

public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

In this example, the Singleton class ensures that only one instance of itself can be created. The getInstance method provides access to that instance, creating it if it doesn't exist.

2. Factory Method Pattern:

  • Purpose: Defines an interface for creating an object but allows subclasses to alter the type of objects that will be created.
  • Use Cases: When you want to delegate the responsibility of object creation to subclasses or when you don’t know the exact type of object needed until runtime.
  • Implementation: Involves an abstract creator class/interface with a method for creating objects, and concrete creator subclasses that implement this method to produce specific objects.
interface Product {
void create();
}
class ConcreteProductA implements Product {
@Override
public void create() {
System.out.println("Creating Product A");
}
}
class ConcreteProductB implements Product {
@Override
public void create() {
System.out.println("Creating Product B");
}
}
abstract class Creator {
public abstract Product factoryMethod();
}
class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}

In this example, we have a Product interface, concrete product classes ConcreteProductA and ConcreteProductB, and abstract creator class Creator with a factory method. Concrete creators ConcreteCreatorA and ConcreteCreatorB implement this method to create specific products.

3. Abstract Factory Pattern:

  • Purpose: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
  • Use Cases: When you need to ensure that the created objects are compatible and belong to the same family (e.g., creating GUI components for a specific platform).
  • Implementation: Involves multiple factory methods (one for each object type), usually organized into an abstract factory interface or class, and concrete factory implementations for different object families.
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}

class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}

@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}

class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}

@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}

Here, AbstractFactory defines factory methods for creating families of related products. ConcreteFactory1 and ConcreteFactory2 implement these methods to create specific products from the first and second product families.

4. Builder Pattern:

  • Purpose: Separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
  • Use Cases: When an object needs to be constructed with numerous configuration options or when you want to create immutable objects.
  • Implementation: Typically involves a director class that orchestrates the building process and a builder interface or class with methods for setting various attributes, which concrete builders implement to create the final object.
class Product {
private String part1;
private String part2;
// ... other parts

public void setPart1(String part1) {
this.part1 = part1;
}

public void setPart2(String part2) {
this.part2 = part2;
}
// ... setters for other parts
}

interface Builder {
void buildPart1();
void buildPart2();
// ... methods for other parts
Product getResult();
}

class ConcreteBuilder implements Builder {
private Product product = new Product();

@Override
public void buildPart1() {
product.setPart1("Part 1");
}

@Override
public void buildPart2() {
product.setPart2("Part 2");
}
// ... methods for other parts

@Override
public Product getResult() {
return product;
}
}

In this example, the Builder interface defines methods for building various parts of a Product. The ConcreteBuilder class implements these methods to construct a Product with specific parts.

5. Prototype Pattern:

  • Purpose: Creates new objects by copying an existing object (the prototype) known as the prototype.
  • Use Cases: When creating an object is more expensive or complex than copying an existing one, or when you need to create objects with varying initial states.
  • Implementation: Typically involves a prototype interface or abstract class, concrete prototype implementations, and a cloning mechanism (deep or shallow copy) to replicate objects.
class Prototype implements Cloneable {
private String field;

public Prototype clone() throws CloneNotSupportedException {
return (Prototype) super.clone();
}

public String getField() {
return field;
}

public void setField(String field) {
this.field = field;
}
}

Here, the Prototype class is a simple example of the prototype pattern. It implements the Cloneable interface and provides a clone method to create copies of itself. This allows you to create new objects by cloning an existing prototype.

Creational design patterns help manage object creation complexity, improve code maintainability, and promote flexibility in handling object instantiation. Choosing the right pattern depends on the specific requirements and constraints of your application.

--

--

Saurav Kumar

Experienced Software Engineer adept in Java, Spring Boot, Microservices, Kafka & Azure.