How to use Builder Pattern in C#

By FoxLearn 12/27/2024 9:53:49 AM   635
The Builder pattern is a creational design pattern that enables the step-by-step construction of complex objects.

It allows the creation of various types and representations of an object using the same construction process, promoting flexibility and separation of concerns in object creation.

Structure

builder pattern in C#

Classes and objects that participate in this pattern include:

  • Builder: Specifies an abstract interface by creating a part of the Product object.
  • ConcreteBuilder: structure and pair parts of one product by implementing the Builder interface. redefine and record the details it creates. Provide an interface that can return the product details created.
  • Director: create the object using the Builder interface
  • Product: is a complex object created. ConcreteBuilder builds internal product details and defines pairing handling, including classes that define details, and interfaces to concatenate parts that produce the final result.

How to Implement Builder Pattern in C#?

public static void Main()
{
    Director director = new Director();

    Builder b1 = new ConcreteBuilder1();
    Builder b2 = new ConcreteBuilder2();

    director.Construct(b1);
    Product p1 = b1.GetResult();
    p1.Show();

    director.Construct(b2);
    Product p2 = b2.GetResult();
    p2.Show();
}

class Director
{
    public void Construct(Builder builder)
    {
        builder.BuildPartA();
        builder.BuildPartB();
    }
}

abstract class Builder
{
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
}

class ConcreteBuilder1 : Builder
{
    private Product _product = new Product();

    public override void BuildPartA()
    {
        _product.Add("PartA");
    }

    public override void BuildPartB()
    {
        _product.Add("PartB");
    }

    public override Product GetResult()
    {
        return _product;
    }
}

class ConcreteBuilder2 : Builder

{
    private Product _product = new Product();

    public override void BuildPartA()
    {
        _product.Add("PartX");
    }

    public override void BuildPartB()
    {
        _product.Add("PartY");
    }

    public override Product GetResult()
    {
        return _product;
    }
}

class Product
{
    private List<string> _parts = new List<string>();
    public void Add(string part)
      _parts.Add(part);

    public void Show()
    {
        Console.WriteLine("\nProduct Parts -------");
        foreach (string part in _parts)
            Console.WriteLine(part);
    }
}

This example will demonstrate the concept of separating the construction process into multiple parts, providing a builder pattern for complex product creation.

1. Define the Products (House and HouseManual)

House represents the actual product, while HouseManual is a manual for the house that describes its features.

public class House
{
    public int Floors { get; set; }
    public int Bedrooms { get; set; }
    public bool HasGarage { get; set; }
    public bool HasGarden { get; set; }
}

public class HouseManual
{
    public string Description { get; set; }
}

2. Define the Builder Interface

IBuilder defines the common methods for building the products.

public interface IBuilder
{
    void Reset();
    void SetFloors(int floors);
    void SetBedrooms(int bedrooms);
    void SetGarage(bool hasGarage);
    void SetGarden(bool hasGarden);
    object GetProduct();
}

3. Concrete Builder for House Construction

HouseBuilder constructs a House object, while HouseManualBuilder constructs a HouseManual object.

public class HouseBuilder : IBuilder
{
    private House _house;

    public HouseBuilder()
    {
        Reset();
    }

    public void Reset()
    {
        _house = new House();
    }

    public void SetFloors(int floors)
    {
        _house.Floors = floors;
    }

    public void SetBedrooms(int bedrooms)
    {
        _house.Bedrooms = bedrooms;
    }

    public void SetGarage(bool hasGarage)
    {
        _house.HasGarage = hasGarage;
    }

    public void SetGarden(bool hasGarden)
    {
        _house.HasGarden = hasGarden;
    }

    public object GetProduct()
    {
        House product = _house;
        Reset();
        return product;
    }
}

4. Concrete Builder for House Manual

public class HouseManualBuilder : IBuilder
{
    private HouseManual _manual;

    public HouseManualBuilder()
    {
        Reset();
    }

    public void Reset()
    {
        _manual = new HouseManual();
    }

    public void SetFloors(int floors)
    {
        _manual.Description += $"Floors: {floors}\n";
    }

    public void SetBedrooms(int bedrooms)
    {
        _manual.Description += $"Bedrooms: {bedrooms}\n";
    }

    public void SetGarage(bool hasGarage)
    {
        _manual.Description += $"Garage: {(hasGarage ? "Yes" : "No")}\n";
    }

    public void SetGarden(bool hasGarden)
    {
        _manual.Description += $"Garden: {(hasGarden ? "Yes" : "No")}\n";
    }

    public object GetProduct()
    {
        HouseManual product = _manual;
        Reset();
        return product;
    }
}

5. The Director Class

The Director class uses the builder objects to construct products in a specific order. It doesn't know the specifics of the products, only how to construct them with the builder methods.

public class Director
{
    public void ConstructBasicHouse(IBuilder builder)
    {
        builder.Reset();
        builder.SetFloors(1);
        builder.SetBedrooms(2);
        builder.SetGarage(true);
        builder.SetGarden(true);
    }

    public void ConstructLuxuryHouse(IBuilder builder)
    {
        builder.Reset();
        builder.SetFloors(3);
        builder.SetBedrooms(5);
        builder.SetGarage(true);
        builder.SetGarden(true);
    }
}

6. Client

In the Application class, the client interacts with the director and builders to construct either a house or its manual.

public class Application
{
    public void BuildHouse()
    {
        Director director = new Director();

        // Build a basic house
        HouseBuilder houseBuilder = new HouseBuilder();
        director.ConstructBasicHouse(houseBuilder);
        House house = (House)houseBuilder.GetProduct();
        Console.WriteLine($"House created with {house.Floors} floors, {house.Bedrooms} bedrooms, " +
            $"{(house.HasGarage ? "with" : "without")} a garage, " +
            $"{(house.HasGarden ? "with" : "without")} a garden.");

        // Build a luxury house manual
        HouseManualBuilder manualBuilder = new HouseManualBuilder();
        director.ConstructLuxuryHouse(manualBuilder);
        HouseManual manual = (HouseManual)manualBuilder.GetProduct();
        Console.WriteLine($"House Manual: \n{manual.Description}");
    }
}

The Builder pattern is especially useful when you need to create complex products (like houses) with many possible configurations (e.g., number of floors, garden, garage) and avoid cluttering the main product class (e.g., House) with a large constructor. The pattern helps separate the construction logic and product representation, making it easier to maintain and modify.