Understanding Creational Design Patterns

Creational patterns focus on the mechanisms of creating objects. By controlling object creation, these patterns allow developers to handle complex object structures and optimize resource management. Some of the most widely used Creational patterns are:

  • Factory Pattern: Defines an interface for creating objects, allowing subclasses to alter the type of objects created.
  • Singleton Pattern: Ensures a class has only one instance and provides a global point of access to it.
  • Builder Pattern: Separates the construction of a complex object from its representation, allowing for step-by-step creation.
  • Prototype Pattern: Creates new objects by copying an existing object, often used when object creation is costly.

Factory Pattern in C#

The Factory pattern is ideal when a class can’t predict the exact type of object it needs. By defining a common interface, this pattern allows for the creation of objects without needing to specify the exact class name. Here’s an example:


public interface IProduct
{
    void Display();
}

public class ProductA : IProduct
{
    public void Display() => Console.WriteLine("Product A");
}

public class ProductB : IProduct
{
    public void Display() => Console.WriteLine("Product B");
}

public class ProductFactory
{
    public static IProduct CreateProduct(string type)
    {
        return type switch
        {
            "A" => new ProductA(),
            "B" => new ProductB(),
            _ => throw new ArgumentException("Invalid type"),
        };
    }
}

// Usage
IProduct product = ProductFactory.CreateProduct("A");
product.Display();

This `ProductFactory` centralizes object creation, which is especially useful in applications where different classes share the same interface.

Singleton Pattern in C#

The Singleton pattern ensures that a class has only one instance and provides a global access point to it. This pattern is beneficial in scenarios where a single object is needed to coordinate actions, such as a logging service or configuration manager:


public class Logger
{
    private static Logger instance;
    private Logger() {}

    public static Logger Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Logger();
            }
            return instance;
        }
    }

    public void Log(string message) => Console.WriteLine($"Log: {message}");
}

// Usage
Logger.Instance.Log("This is a Singleton Logger.");

With the Singleton pattern, the `Logger` class restricts instantiation to a single object, making it ideal for managing global resources.

Builder Pattern in C#

The Builder pattern is useful for constructing complex objects with multiple parts. This pattern enables step-by-step creation without requiring a constructor with numerous parameters:


public class Car
{
    public string Engine { get; set; }
    public string Wheels { get; set; }
    public string Seats { get; set; }
}

public class CarBuilder
{
    private Car car = new Car();

    public CarBuilder AddEngine(string engine)
    {
        car.Engine = engine;
        return this;
    }

    public CarBuilder AddWheels(string wheels)
    {
        car.Wheels = wheels;
        return this;
    }

    public CarBuilder AddSeats(string seats)
    {
        car.Seats = seats;
        return this;
    }

    public Car Build() => car;
}

// Usage
Car car = new CarBuilder().AddEngine("V8").AddWheels("Alloy").AddSeats("Leather").Build();

The `CarBuilder` allows for clear, step-by-step configuration of complex objects, enhancing readability and maintainability.

Prototype Pattern in C#

The Prototype pattern creates new objects by cloning an existing object. This is helpful when object creation is resource-intensive:


public abstract class Shape
{
    public abstract Shape Clone();
}

public class Circle : Shape
{
    public int Radius { get; set; }

    public Circle(int radius)
    {
        Radius = radius;
    }

    public override Shape Clone()
    {
        return new Circle(Radius);
    }
}

// Usage
Circle originalCircle = new Circle(10);
Circle clonedCircle = (Circle)originalCircle.Clone();

Here, `Circle` implements a cloning method, allowing for easy duplication of objects without expensive instantiation processes.

Creational Patterns in Front-End Development with React

While Creational patterns are more common in backend development, they also have applications in front-end frameworks like React. For instance, using a factory function to dynamically create React components is a common approach:


import React from 'react';

interface ButtonProps {
    label: string;
    onClick: () => void;
}

const PrimaryButton: React.FC = ({ label, onClick }) => (
    
);

const SecondaryButton: React.FC = ({ label, onClick }) => (
    
);

const ButtonFactory = (type: "primary" | "secondary", props: ButtonProps) => {
    return type === "primary" ?  : ;
};

// Usage
 alert("Clicked!")} />;

The `ButtonFactory` function creates button components based on the specified type. This pattern simplifies the component creation process, making it easy to manage different button styles and behaviors in a scalable way.

Conclusion

Creational design patterns provide powerful tools for controlling object creation, making code more efficient, scalable, and easier to maintain. By using patterns like Factory, Singleton, Builder, and Prototype, developers can handle complex object creation with confidence. These patterns are versatile and can be applied to backend systems, front-end development in React, and beyond, providing flexibility across different parts of an application.