.NET Design Patterns (The Builder Pattern)

Pattern Type: Creational

Intent: To separate the creation of complex concrete instance of a given object from its creator allowing the same creation process to create other objects of differing types while maintaining the same creation mechanism.

Description

The builder pattern provides a (usually static) instance of a class that constantly creates objects of a given type, usually by calling a complex sequence of steps within its body. This sequence of steps may (and often is) a large number of different processes or other classes that form to make a singular target object.

The builder pattern generally takes, as a parameter to its constructor, an instance of the actual builder class it needs to use to create the final object.

General uses of this pattern usually revolve around representations of the same kind of object but with each having different functionality. For example, the builder pattern often may be deployed to create a logging service, where different versions of the service may log data to different output layers, while maintaining a consistent API and/or data model for the service.

The builder pattern differs from many patterns that create a consistent object model in this fashion in that it typically creates target objects through the use of abstractions in the concrete builder implementation.

Diagram

Builder
Figure 1: The builder pattern

The following items are elements of the builder pattern:

  • Builder: The abstract interface that allows the building of target objects, given concrete builder instances to build them.
  • ConcreteBuilder: This is an actual builder instance taken in as a constructor parameter to the builder itself, which ultimately creates the target objects produced by the builder.
  • Director: The director acts as an overall master object that oversees the builder creation and setup, and makes sure it has the ‘ConcreteBuilders’ it requires.
  • Product: The target object produced by the builder.

Implementation in C#

The first thing to implement is usually your target object, “The Product.” This is just a standard POCO object.

public class Product
{
   public Product()
   {
   }

   public string ProductPropertyOne { get; set; }

   public int ProductPropertyTwo { get; set; }

   public override string ToString()
   {
      return string.Format("Property One: {0}, Property Two: {1}",
         ProductPropertyOne, ProductPropertyTwo);
    }

}

You then need the abstract builder class. Here, I’ve chosen to implement this as an Interface, but you could just as easily implement this as an abstract class. Both approaches work well.

public interface IProductBuilder
{
   void SetPropertyOne(string value);
   void SetPropertyTwo(int value);
   Product GetResult();
}

Once you have an interface (or abstract), you then use that to create concrete implementations. An implementation to create “Product Type One” might look like the following:

public class ProductOneBuilder : IProductBuilder
{
   private Product _product;

   public ProductOneBuilder()
   {
      _product = new Product();
   }

   public void SetPropertyOne(string value)
   {
      _product.ProductPropertyOne = value;
   }

   public void SetPropertyTwo(int value)
   {
      _product.ProductPropertyTwo = value;
   }

   public Product GetResult()
   {
      return _product;
   }
}

As long as it implements the interface defined in the builder, everything should work okay.

Just to demonstrate the process, let’s suppose you now wanted to create a “Product Two.” You could add the following:

public class ProductTwoBuilder : IProductBuilder
{
   private Product _product;

   public ProductTwoBuilder()
   {
      _product = new Product();
   }

   public void SetPropertyOne(string value)
   {
      _product.ProductPropertyOne = "[" + value + "]";
   }

   public void SetPropertyTwo(int value)
   {
      _product.ProductPropertyTwo = value * 2;
   }

   public Product GetResult()
   {
      return _product;
   }
}

As you can see again, it follows the interface but implements slightly different methodology.

The final part of the puzzle is the director class. This class calls the required pieces to produce the final result.

public class Director
{
   public Product Construct()
   {
      ProductOneBuilder builder = new ProductOneBuilder();

      builder.SetPropertyOne("Red");
      builder.SetPropertyTwo(4);

      return builder.GetResult();
   }
}

If you have a Design Pattern you’d like to see implemented in C#, drop me a comment below. Until next month, practice makes perfect.

Shawty

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read