avatarEthiraj Srinivasan

Summary

The provided web content offers an in-depth exploration of creational design patterns, specifically focusing on the Singleton and Prototype patterns, and demonstrates their practical implementation in Java.

Abstract

The article delves into the realm of creational design patterns, which are essential for object creation in a manner that enhances encapsulation, decoupling, and flexibility. It builds upon previous discussions on the Factory Method and Builder patterns by introducing two additional patterns: the Singleton pattern, which ensures a single instance of a class with global access, and the Prototype pattern, which facilitates object creation by cloning existing instances. The author provides Java code examples to illustrate the application of these patterns, such as a Logger class for the Singleton pattern and a Shape interface with a Circle implementation for the Prototype pattern. The article emphasizes the benefits of these patterns in scenarios where object creation is costly or when a shared resource is necessary, and it concludes by encouraging readers to apply these design patterns in their object creation processes.

Opinions

  • The author advocates for the use of creational patterns to improve object creation, suggesting they are crucial for well-designed software.
  • The Singleton pattern is presented as a solution for scenarios requiring a single global instance, such as centralized logging.
  • The Prototype pattern is recommended for situations where creating objects from scratch is resource-intensive, advocating for cloning as a more efficient alternative.
  • The author emphasizes the importance of understanding the nuances of each pattern, such as the need for deep copying when using Java's clone() method to handle mutable fields.
  • By providing real-world examples and encouraging further exploration through their blog and social media, the author conveys a strong belief in the practicality and utility of design patterns in software development.

From Blueprint to Reality: Unleashing the Potential of Creational Patterns

A Comprehensive Exploration of Design Patterns for Crafting Objects with Precision and Elegance

Photo by Andreas Felske on Unsplash

In my previous article Demystifying Creational Patterns: A Roadmap to Effective Object Creation, I stated the need for creational patterns and illustrated them using two creational patterns: Factory Method Pattern and Builder Pattern. So in short creational patterns focus on creating objects in a way that promotes encapsulation, decoupling, and flexibility.

In this article, we will look at the following two design patterns in detail

  • Singleton pattern
  • Prototype pattern

Singleton Pattern

Singleton pattern are used to make sure that only one instance of a class is created and provides global access to it. It uses a private constructor to prevent direct object instantiation and the static method provides access to the single instance.

Singleton Class (Same User behind every door)

Lets us look at an example:

public class Logger {
    private static Logger instance;
    
    // Private constructor to prevent direct instantiation
    private Logger() {
        // Initialization code, if needed
    }
    
    // Static method to provide access to the single instance
    public static Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }
    
    // Method to log a message
    public void log(String message) {
        System.out.println("Logging message: " + message);
        // Log message implementation goes here
    }
}

In the example above Logger class has a private constructor Logger and getInstance method which provides a single instance of the class.

public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getInstance();
        logger.log("An important message");

        // Trying to create a new instance will give us the existing instance
        Logger anotherLogger = Logger.getInstance();
        anotherLogger.log("Another message");

        // Output:
        // Logging message: An important message
        // Logging message: Another message
    }
}

The above example states that only one instance of the class gets created regardless of the number of times getInstance() is called.

The singleton pattern ensures that all the components share the same logger instance. This helps in centralized logging and ensures all messages are recorded by the same logger object.

Thus singleton pattern is used when one instance of an object needs to be created and has to be shared across other components.

Prototype pattern

Prototype pattern allows the creation of objects by cloning existing instances thereby reducing the need to create new instances from scratch. It has a prototype object and uses that object to create new objects by cloning. It is used when new object creation is expensive and complex.

Photo by Kumpan Electric on Unsplash

Let’s consider a scenario where we have a design application that can create and customize shapes. Prototype pattern is used to clone the existing shape objects and modify them as per requirement instead of creating each shape object from scratch.

// Prototype interface
public interface Shape extends Cloneable {
    void draw();
    Shape clone();
}

// Concrete implementation of Shape
public class Circle implements Shape {
    private int radius;

    public Circle(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a circle with radius " + radius);
    }

    @Override
    public Shape clone() {
        try {
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

// Client code
public class GraphicDesignApp {
    public static void main(String[] args) {
        // Create a prototype circle
        Circle circlePrototype = new Circle(10);

        // Clone the circle and customize
        Shape circle1 = circlePrototype.clone();
        circle1.draw();

        ((Circle) circle1).setRadius(15);
        circle1.draw();

        // Clone the circle again and customize
        Shape circle2 = circlePrototype.clone();
        ((Circle) circle2).setRadius(8);
        circle2.draw();
    }
}

The shape interface has the clone and draw method. The circle class implements the interface and has its modification of the radius field.

In the GraphicDesignApp circlePrototype object is created and new circle objects are created by cloning and modifying the radius and then draw() is called to visualize it.

Do note that clone() in Java performs a shallow copy. If there are mutable fields a deep copy must be performed to create a cloned object.

Thus prototype pattern is useful when creating complex objects and each object requires a variation. It makes use of the existing object to reduce the overhead of object creation.

Do note that each creational design pattern has its own set of requirements and constraints.Hope the above explanations and implementation examples give you clarity on the creational designer pattern.Happy creating objects !!!

Originally published at https://ethigeek.com.

Thank you for your comments and for sharing my stories to reach a broader audience.

If you like my article and would like to support me, make sure to:

Design Patterns
Java
Programming
Software Development
Architecture
Recommended from ReadMedium