Introduction

In the previous article, "Singleton Pattern: Ensuring a Single Instance in.NET Core," we learned that a class has only one object and provides a global point to use with it. This pattern is especially useful for managing shared resources like configuration settings, logging mechanisms, or database connections. In multithreaded environments, it’s crucial to implement Singleton properly to prevent race conditions.

In this article, we’ll explore the Builder Pattern, a step-by-step design process for building complex objects. We will illustrate this example with examples of computers. Following this approach, we can manage the complexity of producing these products, ensuring their cleanliness and simplicity of products.

Understanding the Builder Pattern

The Builder Pattern is a creational design pattern that separates the construction of a complex object from its final representation. Unlike other patterns, which might require different constructors or configuration methods, the Builder allows the object to be created step by step, each part configurable and replaceable. This pattern is ideal when an object needs to be created with various configurations or when the construction process involves multiple steps.

Key Components of Builder Pattern

Example in C#

Let's illustrate the Builder Pattern with a practical example of constructing computer objects with various configurations.

1. Define the Product Class

Computer.cs

namespace Builder_Pattern_Demo
{
    public class Computer
    {
        public string CPU { get; set; }
        public int RAM { get; set; }
        public int Storage { get; set; }
        public bool HasGraphicsCard { get; set; }

        public override string ToString()
        {
            return $"Computer with CPU: {CPU}, RAM: {RAM}GB, Storage: {Storage}GB, Graphics Card: {HasGraphicsCard}";
        }
    }
}

Explanation

2. Define the Builder Interface

IComputerBuilder.cs

namespace Builder_Pattern_Demo
{
    public interface IComputerBuilder
    {
        void SetCPU(string cpu);
        void SetRAM(int ram);
        void SetStorage(int storage);
        void SetGraphicsCard(bool hasGraphicsCard);
        Computer GetComputer();
    }
}

Explanation

3. Implement the Concrete Builder

ComputerBuilder.cs

namespace Builder_Pattern_Demo
{
    public class ComputerBuilder : IComputerBuilder
    {
        private Computer _computer = new Computer();

        public void SetCPU(string cpu)
        {
            _computer.CPU = cpu;
        }

        public void SetRAM(int ram)
        {
            _computer.RAM = ram;
        }

        public void SetStorage(int storage)
        {
            _computer.Storage = storage;
        }

        public void SetGraphicsCard(bool hasGraphicsCard)
        {
            _computer.HasGraphicsCard = hasGraphicsCard;
        }

        public Computer GetComputer()
        {
            return _computer;
        }
    }

}

Explanation

4. Define the Director

ComputerDirector.cs

namespace Builder_Pattern_Demo
{
    public class ComputerDirector
    {
        private readonly IComputerBuilder _builder;

        public ComputerDirector(IComputerBuilder builder)
        {
            _builder = builder;
        }

        public void BuildGamingPC()
        {
            _builder.SetCPU("Intel i9");
            _builder.SetRAM(32);
            _builder.SetStorage(1024);
            _builder.SetGraphicsCard(true);
        }

        public void BuildWorkstation()
        {
            _builder.SetCPU("Intel Xeon");
            _builder.SetRAM(64);
            _builder.SetStorage(2048);
            _builder.SetGraphicsCard(false);
        }
    }

}

Explanation

5. Client Code

Program.cs

using Builder_Pattern_Demo;

class Program
{
    static void Main(string[] args)
    {
        IComputerBuilder builder = new ComputerBuilder();
        ComputerDirector director = new ComputerDirector(builder);

        // Build a gaming PC
        director.BuildGamingPC();
        Computer gamingPC = builder.GetComputer();
        Console.WriteLine("Uday Dodiya's Gaming PC: " + gamingPC);

        // Build a workstation
        director.BuildWorkstation();
        Computer workstation = builder.GetComputer();
        Console.WriteLine("Uday Dodiya's Workstation: " + workstation);
    }
}

Explanation

File Structure For the Above Example.

File structure

Output

Visual Studio Debug

Real-World Use Cases

Benefits of the builder pattern

Summary

The Builder Pattern provides a structured approach to constructing complex objects. By breaking down the construction process into manageable steps, we can create different configurations of objects efficiently. In this article, we demonstrated how to build various types of computers using the Builder Pattern.

Next Steps

In the next article,"Prototype Pattern: Cloning Objects in C#", we will explore the Prototype Pattern and its use in creating new objects by cloning existing ones. This pattern is particularly useful when object creation is expensive or involves complex initialization.

If you find this article valuable, please consider liking it and sharing your thoughts in the comments.

Thank you, and happy coding.