Patterns. Builder pattern. Implementation in Java. Example

Builder pattern. Implementation in Java. Example

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. Figure

The Builder pattern is a generative pattern. The pattern is intended to produce objects. The structure of the Builder pattern is shown in Figure 1.

The structure of the Builder pattern. Generalized case

Figure 1. The structure of the Builder pattern. Generalized case

 

2. An example of implementation of the Builder pattern in Java. Creating a complex number object
2.1. The task. The picture to be implemented

The example demonstrates the implementation of the Builder pattern, which is based on the structure shown in Figure 2. The product is the Complex class, which defines a complex number consisting of a real and an imaginary part. In the Director class, the Construct() method constructs the two parts of the complex number. The resulting number is returned to the client in the GetResult() method.

The structure of the Builder pattern showing the solution of the problem

Figure 2. The structure of the Builder pattern showing the solution of the problem

 

2.2. Program code for solving the problem

The implementation of the Builder pattern in Java is as follows

 

// Implementation of the Builder pattern in Java.

// The class that is the product is a complex number
class Complex {
  public double re; // real part of a complex number
  public double im; // imaginary part of a complex number
}

// A class that implements an interface with a client
class Builder{
  // Methods that are passed to the client
  void CreateComplex() {}
  void BuildPart1(int part1) {}
  void BuildPart2(int part2) {}
  Complex GetResult() { return null; }
}

// A class that is a concrete builder
class ConcreteBuilder extends Builder {
  // Reference
  private Complex currentBuilder;

  // Constructor
  ConcreteBuilder() {
    currentBuilder = null;
  }

  // Overriding methods defined in the Builder class
  void CreateComplex() {
    System.out.println("ConcreteBuilder.CreateComplex()");
    currentBuilder = new Complex();
  }

  // Build part 1
  void BuildPart1(int part1) {
    currentBuilder.re = part1;
  }

  // Build part 2
  void BuildPart2(int part2) {
    currentBuilder.im = part2;
  }

  // Return a complex number for the client
  Complex GetResult() {
    return currentBuilder;
  }
}

// Class-disposer
class Director {
  // Method constructing parts
  // gets a reference to the class that implements the interface with the client
  void Construct(Builder builder) {
    // Create a product
    builder.CreateComplex();

    // Build part 1
    builder.BuildPart1(15);

    // Build part 2
    builder.BuildPart2(30);
  }
}

public class TestBuilder {
  public static void main(String[] args) {
    // The main() function acts as a client
    // 1. Declare complex number reference (product)
    Complex C;

    // 2. Create a concrete instance of the ConcreteBuilder class
    ConcreteBuilder B = new ConcreteBuilder();

    // 3. Create a class-disposer and configure it with product B
    Director D = new Director();
    D.Construct(B);

    // 4. Pass the created product to the client
    C = B.GetResult();

    // 5. Print the value of a complex number (for verification)
    System.out.println("C.re = " + C.re);
    System.out.println("C.im = " + C.im);
  }
}

 

2.3. Explanation to the solution

Let’s explain some code snippets. The result of the Builder pattern should be a class object. In our case, the result of the pattern operation is an object of the Complex class. Optionally, you can replace the Complex class as you see fit.

The Builder class is used to communicate with the client. This class has a GetResult() method that returns a constructed object of type Complex to the client. This is the result of the pattern.

The Director class declares one single Construct() method that creates an instance of the Builder class and builds its parts – the BuildPart1() and BuildPart2() methods. In our case, the parts are the real part of the complex number (the variable re of the Complex class) and the imaginary part of the complex number (the im variable of the Complex class). The Construct() method is called by the client to construct an object. Various variations are allowed here to obtain the desired object.

A concrete instance (object) of the Complex class is directly created in the ConcreteBuilder class and, through the mechanism of virtual functions (dynamic polymorphism), is returned to the client as a reference to the Builder class. Thanks to polymorphism and inheritance, you can add builder classes inherited from the Builder class (ConcreteBuilder2, ConcreteBuilder3, etc.) to the structure, which will build (create) various products.

 

2.4. The result of the program

After starting the program will give the following result

ConcreteBuilder.CreateComplex()
C.re = 15.0
C.im = 30.0

 

3. Using the Builder pattern for two specific builders. Java solution

In the Builder pattern, the number of concrete builder classes (ConcreteBuilder) can be several. This example demonstrates the use of two specific builders.

3.1. Task

Using the structure of the Builder pattern, develop the construction of objects of the following classes:

  • a class containing means for converting a string from binary to decimal;
  • a class containing means for converting a string from octal to decimal.

The product of the classes is a convertible string (type String).

 

3.2. Block diagram of the problem solution

The first step in solving the problem is to build a structural diagram. In our case, the block diagram is shown in Figure 3.

Builder pattern. Block diagram of the problem solution

Figure 3. Block diagram of the problem solution

As you can see from the diagram, the solution to the problem is based on the following classes:

  • Builder – a class that implements an interface with a client;
  • Director is the manager class. Contains a Construct() method that constructs an object of type Builder;
  • Convert_2_to_10 – a class containing means for converting a string from binary to decimal;
  • Convert_8_to_10 – a class containing means for converting a string from octal to decimal.

The program also uses the TestBuilder class, which contains a main() function that demonstrates how the client works.

 

3.3. The program code for solving the problem

In Java, the program code for solving the problem is as follows.

 

// Implementation of the Builder pattern in Java.

// A class that implements an interface with a client
interface Builder {
  void Convert(String str2);
  String GetResult();
}

// Class containing means for converting numbers
// from binary to decimal
class Convert_2_to_10 implements Builder {

  private String str10; // Decimal number - converted number

  // Conversion method Convert () - gets a number as a string in binary system
  public void Convert(String str2) {
    // Need to convert str2 to str10
    // 1. Check if str2 is correct, if not, then convert to an empty string
    for (int i=0; i<str2.length(); i++)
      if (!((str2.charAt(i)=='0') || (str2.charAt(i)=='1'))) {
        str10 = "Error. Incorrect value."; // string str2 contains an invalid character
        return;
      }

    // 2. Converting from binary string to decimal
    int power = 1;
    int number = 0;
    int pos;

    for (int i=0; i<str2.length(); i++) {
      // power with base 2
      if (i==0)
        power = 1;
      else
        power = power*2;

      // position in string
      pos = str2.length()-i-1;

      // bits are added where character is 1
      if (str2.charAt(pos) == '1')
        number = number + power;
    }

    // 3. Converting a decimal number to a decimal string
    str10 = "";
    while (number>0) {
      str10 = (number%10) + str10;
      number = number / 10;
    }
  }

  public String GetResult() {
    return str10;
  }
}

// Class containing converters
// from octal to decimal
class Convert_8_to_10 implements Builder {

  private String str10; // result

  // Conversion method Convert () - gets a number as a string in octal
  public void Convert(String str8) {
    // Need to convert str8 to str10
    // 1. Check if str8 is correct, if not, then convert to empty string
    for (int i=0; i<str8.length(); i++)
      if ((str8.charAt(i)<'0') || (str8.charAt(i)>'7')) {
        str10 = "Error. Incorrect value."; // string str2 contains an invalid character
        return;
      }

    // 2. Converting from an octal string to a decimal number
    int power = 1;
    int number = 0;
    int pos;

    for (int i=0; i<str8.length(); i++) {
      // power with base 8
      if (i==0)
        power = 1;
      else
        power = power*8;

      // position in string
      pos = str8.length()-i-1;

      // formula for calculating the term
      number = number + (str8.charAt(pos)-'0')*power;
    }

    // 3. formula for calculating the addendum
    str10 = "";
    while (number > 0) {
      str10 = (number % 10) + str10;
      number = number / 10;
    }
  }

  // Implementation of GetResult() method
  public String GetResult() {
    return str10;
  }
}

// Class-manager
class Director {
  // Method constructing parts
  // gets a reference to the class that implements the interface with the client
  void Construct(Builder builder) {
    // Build a product for a client
    builder.Convert("100010");
  }

  // Builds a class object for the octal number system
  void Construct2(Builder builder) {
    builder.Convert("770");
  }
}

public class TestBuilder {

  public static void main(String[] args) {
    // The main () function acts as a client
    // 1. Constructing an object of class Convert_2_to_10
    // 1.1. Create a specific instance of the Convert_2_to_10 class
    Convert_2_to_10 obj1 = new Convert_2_to_10();

    // 1.2. Create a class-manager and configure it with the obj1 product
    Director D = new Director();
    D.Construct(obj1);

    // 1.3. Get the result string and print it
    String res = obj1.GetResult();
    System.out.println("res_2 = " + res);

    // ----------------------------------------------------------------
    // 2. Constructing an object of class Convert_8_to_10
    // 2.1. Create a specific instance of the Convert_8_to_10 class
    Builder obj2 = new Convert_8_to_10(); // You can create an instance like that

    // 2.2. Create a new instance
    D.Construct2(obj2);

    // 2.3. Return the constructed instance to the client
    String res2 = obj2.GetResult();
    System.out.println("res_8 = " + res2);
  }
}

As you can see from the code, the communication of concrete builder classes (Convert_2_to_10, Convert_8_to_10) with the client is carried out through the Builder interface and not through the class, as shown in the previous example. Using an interface instead of a class is shown for demonstration purposes.

According to the definition of the Builder pattern, methods in a class can do nothing. An interface or class can be replaced with an abstract class. All this is determined by the specifics of the task.

 

3.4. The result of the program

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

res_2 = 34
res_8 = 504

 


Related topics