dofactory C# Builder

发布时间 2023-09-12 11:27:51作者: ChuckLu

The Builder pattern is a creational design pattern that allows for the construction of complex objects step by step. It separates the construction of a complex object from its representation, enabling the same construction process to create different representations.

Why we need it:

  1. Complex Object Creation: When an object has a complex construction process with multiple steps, the Builder pattern provides a way to encapsulate this process and hide the complexity from the client.

  2. Variability in Object Construction: It allows for the creation of different configurations or representations of the same object, depending on the needs of the application.

  3. Immutability: It's particularly useful when you want to create objects that are immutable, meaning their state cannot be changed after they are created.

When to use it:

The Builder pattern is useful in the following situations:

  1. Creating Complex Objects: When you have an object that requires a large number of steps or parameters to be properly constructed.

  2. Creating Different Configurations: When you need to create objects with different configurations or optional features.

  3. Ensuring Immutability: When you want to ensure that the created objects are immutable.

How to use it:

Here's a step-by-step guide on how to use the Builder pattern:

  1. Define the Product:

    • This is the complex object you want to construct. It should have a set of attributes or properties that need to be set during the construction process.
  2. Create the Builder Interface:

    • Define an interface that declares the methods for constructing the different parts of the product. Each method corresponds to a step in the construction process.
  3. Implement Concrete Builders:

    • Create one or more classes that implement the builder interface. Each concrete builder is responsible for constructing a specific version or representation of the product.
  4. Create the Director (Optional):

    • The director is responsible for orchestrating the construction process. It takes a builder as input and guides it through the steps to build the product. This step is optional, and you can also let the client directly interact with the builder.
  5. Client Code:

    • The client decides which builder to use and, if a director is present, it instructs the director to use that builder for construction.

Example:

Let's consider an example of building a Computer object with different components like CPU, RAM, Storage, etc., using the Builder pattern:

// Step 1: Define the Product (Computer)
class Computer
{
    public string CPU { get; set; }
    public string RAM { get; set; }
    public string Storage { get; set; }
    // Other properties...
}

// Step 2: Create the Builder Interface
interface IComputerBuilder
{
    void SetCPU();
    void SetRAM();
    void SetStorage();
    Computer GetComputer();
}

// Step 3: Implement Concrete Builders
class GamingComputerBuilder : IComputerBuilder
{
    private Computer computer = new Computer();

    public void SetCPU()
    {
        computer.CPU = "Gaming CPU";
    }

    public void SetRAM()
    {
        computer.RAM = "16GB Gaming RAM";
    }

    public void SetStorage()
    {
        computer.Storage = "1TB SSD";
    }

    public Computer GetComputer()
    {
        return computer;
    }
}

class OfficeComputerBuilder : IComputerBuilder
{
    private Computer computer = new Computer();

    public void SetCPU()
    {
        computer.CPU = "Office CPU";
    }

    public void SetRAM()
    {
        computer.RAM = "8GB RAM";
    }

    public void SetStorage()
    {
        computer.Storage = "500GB HDD";
    }

    public Computer GetComputer()
    {
        return computer;
    }
}

// Step 4: Create the Director (Optional)
class ComputerEngineer
{
    private IComputerBuilder builder;

    public ComputerEngineer(IComputerBuilder builder)
    {
        this.builder = builder;
    }

    public void ConstructComputer()
    {
        builder.SetCPU();
        builder.SetRAM();
        builder.SetStorage();
    }

    public Computer GetComputer()
    {
        return builder.GetComputer();
    }
}

// Step 5: Client Code
class Program
{
    static void Main()
    {
        IComputerBuilder gamingBuilder = new GamingComputerBuilder();
        ComputerEngineer gamingEngineer = new ComputerEngineer(gamingBuilder);

        gamingEngineer.ConstructComputer();
        Computer gamingComputer = gamingEngineer.GetComputer();

        Console.WriteLine($"Gaming Computer: CPU={gamingComputer.CPU}, RAM={gamingComputer.RAM}, Storage={gamingComputer.Storage}");
    }
}

In this example:

  • We have a Computer class representing the product.
  • We define an interface IComputerBuilder with methods to set CPU, RAM, and Storage.
  • We implement two concrete builders (GamingComputerBuilder and OfficeComputerBuilder) which specify the steps to build different configurations of a computer.
  • Optionally, we have a ComputerEngineer class that guides the construction process.
  • In the client code, we choose a builder (in this case, GamingComputerBuilder), instruct the engineer to construct the computer, and then retrieve the constructed computer.

This example illustrates how the Builder pattern can be used to construct complex objects with different configurations. It provides flexibility and separation between the construction process and the representation of the object.