Patterns. Implementing the Builder pattern in C#

Implementing the Builder pattern in C#

Before studying this topic, it is recommended that you familiarize yourself with the following topic:


Contents


Search other websites:




1. The structure of the Builder pattern

In the most general case, the structure of the Builder pattern is shown in Figure 1.

The structure of Builder pattern

Figure 1. The structure of Builder pattern

 

2. Implementation of Builder pattern in C#. Example
2.1. Block diagram of the problem solution

The example demonstrates the implementation of the Builder pattern in C#, the structure of which is shown in Figure 2.

Builder pattern. Building the product of 3 parts

Figure 2. Builder pattern. Building the product of 3 parts

The following classes are declared:

  • Product – a class that is a product (the result of a pattern). This is an arbitrary class. For demonstration purposes, this class declares three integer variables, each of which is conventionally considered part of the product;
  • Builder is an abstract class that serves as the interface between the Director and the class that creates a concrete object (ConcreteBuilder);
  • ConcreteBuilder – a class that builds a concrete object;
  • Director is a class that is a manager. This class builds (configures) an object of the ConcreteBuilder class for use by the client.
  • Program is a class that acts as a client. This class implements the main() function, which demonstrates the client’s work. The client contacts the Director to build an object of the ConcreteBuilder class. The constructed object is then returned to the client in the GetResult() method.

 

2.2. Program in C#

The text of the program in the C# programming language is as follows

using System;

namespace ConsoleApp8
{
  // Builder pattern. An example implementation in C#
  // 1. A class serving as a product. Contains three parts
  class Product
  {
    // Internal variables
    private int part1, part2, part3;

    // Constructor
    public Product()
    {
      part1 = 0;
      part2 = 0;
      part3 = 0;
    }

    // Access methods
    public int GetPart1() { return part1; }
    public int GetPart2() { return part2; }
    public int GetPart3() { return part3; }

    public void SetPart1(int part1)
    {
      this.part1 = part1;
    }

    public void SetPart2(int part2)
    {
      this.part2 = part2;
    }

    public void SetPart3(int part3)
    {
      this.part3 = part3;
    }
  }

  // 2. A class that serves as an interface between a director and a specific builder
  abstract class Builder
  {
    // Method that creates the product
    public abstract void CreateProduct();

    // Methods that build parts of a product
    public abstract void BuildPart1(int part);
    public abstract void BuildPart2(int part);
    public abstract void BuildPart3(int part);

    // Method that returns the product to the client
    public abstract Product GetProduct();
  }

  // The class is a concrete builder, inherits the abstract class Builder
  class ConcreteBuilder : Builder
  {
    // Internal variable - reference to product
    private Product currentBuilder;

    // Methods that are declared in the abstract Builder class, they need to be implemented
    public override void CreateProduct()
    {
      currentBuilder = new Product();
    }

    public override void BuildPart1(int part)
    {
      currentBuilder.SetPart1(part);
    }

    public override void BuildPart2(int part)
    {
      currentBuilder.SetPart2(part);
    }

    public override void BuildPart3(int part)
    {
      currentBuilder.SetPart3(part);
    }

    public override Product GetProduct()
    {
      return currentBuilder;
    }
  }

  // Class-manager, contains methods for constructing the Product object from parts
  class Director
  {
    // Reference to Builder
    private Builder builder;

    // Constructor - initialized by a Builder instance
    public Director(Builder _builder)
    {
      builder = _builder;
    }

    // A method that builds an object of the Product class from parts
    public void Construct()
    {
      // Construct an instance of the Product class
      builder.CreateProduct();
      builder.BuildPart1(10);
      builder.BuildPart2(20);
      builder.BuildPart3(30);
    }
  }

  // Class containing the client function
  class Program
  {
    static void Main(string[] args)
    {
      // This is a client
      // 1. Declare a reference to the product
      Product product;

      // 2. Create a specific builder
      Builder B = new ConcreteBuilder();

      // 3. Create a manager and configure it with a builder
      Director D = new Director(B);

      // 4. Call methods of building a product - entrust it to the manager
      D.Construct();

      // 5. Return the built product to the client
      product = B.GetProduct();

      // 6. Check how the product is built
      Console.WriteLine("product.part1 = {0}", product.GetPart1());
      Console.WriteLine("product.part2 = {0}", product.GetPart2());
      Console.WriteLine("product.part3 = {0}", product.GetPart3());
    }
  }
}

 

2.3. The result of the program
product.part1 = 10
product.part2 = 20
product.part3 = 30

 

3. An example of using the Builder pattern to generate arrays of random numbers
3.1. Task

Using the means of the C# language and the capabilities of the Builder pattern, develop a program for generating objects that are arrays of random numbers. Arrays of random numbers are represented by the following classes:

  • ArrayRandomInt – an array of integers. A range is specified for this array;
  • ArrayRandomChar – an array of random characters from ‘A’ to ‘Z’.

 

3.2. Figure, reflecting the block diagram of the task solution

Figure 3 shows the structure of the Builder pattern, which reflects the solution to this problem.

Builder pattern. Generating objects - arrays of random numbers

Figure 3. Builder pattern. Generating objects – arrays of random numbers

As you can see from the figure, the manager class can use the two builder classes BuildRandomInt and BuildRandomChar.

 

3.3. Solution. C# program. Console Application

The text of the program with the solution to the problem is as follows.

using System;

namespace ConsoleApp9
{
  // 1. Classes that are products
  // 1.1. ArrayRandomInt - an array of random numbers
  class ArrayRandomInt
  {
    // Declare internal variable - array instance
    private int[] A;

    // Class constructor with three parameters
    public ArrayRandomInt(int count, int min, int max)
    {
      // Create an instance of the Random class
      Random rndNum = new Random();

      // Construct an array of random numbers
      A = new int[count];
      for (int i = 0; i < count; i++)
      {
        A[i] = rndNum.Next(min, max + 1);
      }
    }

    // Method that returns an array
    public int[] GetArrayInt()
    {
      return A;
    }
  }

  // 1.2. Array of characters from 'A' to 'Z'
  class ArrayRandomChar
  {
    // Array of random characters from 'A' to 'Z'
    private char[] A;

    public ArrayRandomChar(int count)
    {
      // Create an instance of Random class
      Random rndChar = new Random();

      // Build array A
      A = new char[count];
      int t;

      for (int i = 0; i < count; i++)
      {
        // Get a random character from 'A' to 'Z'
        A[i] = (char)(rndChar.Next((int)('Z' - 'A' + 1)) + (int)'A');
      }
    }

    // Method that returns an array
    public char[] GetArrayChar()
    {
      return A;
    }
  }

  // 2. A class that serves as an interface with a client to generate an object of type int
  class Builder
  {
    // The class declares the methods provided to the manager class
    virtual public void BuildArrayInt(int count, int min, int max) { }
    virtual public void BuildArrayChar(int count) { }

    // Methods that return specific objects to the client
    virtual public ArrayRandomInt GetResultInt()
    {
      return null;
    }

    virtual public ArrayRandomChar GetResultChar()
    {
      return null;
    }
  }

  // 3. Classes - builders of ArrayRandomInt and ArrayRandomChar instances
  class BuildRandomInt : Builder
  {
    private ArrayRandomInt A;

    override public void BuildArrayInt(int count, int min, int max)
    {
      // Construct an instance of the ArrayRandomInt class
      A = new ArrayRandomInt(count, min, max);
    }

    override public ArrayRandomInt GetResultInt()
    {
      return A;
    }
  }

  class BuildRandomChar : Builder
  {
    private ArrayRandomChar A;

    public override void BuildArrayChar(int count)
    {
      A = new ArrayRandomChar(count);
    }

    public override ArrayRandomChar GetResultChar()
    {
      return A;
    }
  }

  // 4. Class, acting manager
  class Director
  {
    private Builder builder;

    // Class constructor
    public Director(Builder _builder)
    {
      builder = _builder;
    }

    // Method that builds an array of random numbers
    public void ConstructInt()
    {
      // Construct an array of 10 integers ranging from 5 to 15
      builder.BuildArrayInt(10, 5, 15);
    }

    public void ConstructChar()
    {
      // Construct an array of 15 characters of type char
      builder.BuildArrayChar(15);
    }
  }

  // Client class
  class Program
  {
    static void Main(string[] args)
    {
      // This is a client
      // 1. Generating an ArrayRandomInt object
      // 1.1. Declare a product
      ArrayRandomInt AI; // This is the result - an array object of integers

      // 1.2. Declare a builder class
      Builder BI = new BuildRandomInt();

      // 1.3. Declare a manager and configure it with a specific builder
      Director D = new Director(BI);
      D.ConstructInt(); // Construct an object-array of integers

      // 1.4. Pass array to client
      AI = BI.GetResultInt();

      // 1.5. Return the result
      int[] arrInt = AI.GetArrayInt();
      Console.WriteLine("Array AI:");
      for (int i = 0; i < arrInt.Length; i++)
        Console.Write("{0}   ", arrInt[i]);
      Console.WriteLine();

      // -----------------------------------------
      // 2. Generating an ArrayRandomChar object
      // 2.1. Declare a product
      ArrayRandomChar AC;

      // 2.2. Declare a class-builder
      BuildRandomChar BC = new BuildRandomChar();

      // 2.3. Declare a manager class and configure it a builder
      Director DC = new Director(BC);

      // 2.4. Construct an array of char values
      DC.ConstructChar();

      // 2.5. Pass array to client
      AC = BC.GetResultChar();

      // 2.6. Print the resulting array for verification
      char[] arrChar = AC.GetArrayChar();
      Console.WriteLine("Array AC:");
      for (int i = 0; i < arrChar.Length; i++)
        Console.Write("{0} ", arrChar[i]);
      Console.WriteLine();
    }
  }
}

 

3.4. Explanation of the program

As you can see from Figure 3, the program uses two builder classes BuildRandomInt and BuildRandomChar containing two methods for constructing class objects:

  • method BuildArrayInt() – creates an instance of the ArrayRandomInt class ;
  • method BuildArrayChar() – creates an instance of the ArrayRandomChar class.

The ArrayRandomInt and ArrayRandomChar classes are products that are passed to the client.

The Director class is the manager class. This class implements two methods ConstructInt() and ConstructChar(), from which the BuildArrayInt() and BuildArrayChar() methods are called with specific parameters (array length, range of values).

The Builder class serves as the interface between the Director manager class and the builder classes BuildRandomInt and BuildRandomChar.

Another variant of the task implementation was possible, in which the Builder class was divided into two subclasses, for example, BuilderInt and BuilderChar.

 

3.5. The result of the program

After running for execution, the program will give the following result

Array AI:
5 10 14 7 5   11 10 8 9 14
Array AC:
J M G N M S C H N L S Y E L V

 


Related topics