Joshua Bloch’s Builder Pattern in C#

Having spent a lot of time programming in Java over the last two years, I’ve made heavy use of Joshua Bloch‘s Java Builder pattern (also Effective Java Item 2).

Recently, I’ve started a fairly large project in C# 3.0. As it happens, there came a point where I wanted to use a pattern similar to Bloch’s Builder. However, as anyone who tries to use this pattern in C# will quickly find out, Bloch’s Builder doesn’t translate perfectly to C#.

Here is how Bloch’s Builder looks in C# (with changes made only for syntax):

public class NutritionFacts
{
  public int ServingSize { get; private set; }
  public int Servings { get; private set; }
  public int Calories { get; private set; }
  ...
 
  public class Builder
  {
    private int ServingSize { get; set; }
    private int Servings { get; set; }
    private int Calories { get; set; }
 
    public Builder(int servingSize, int servings)
    {
      ServingSize = servingSize;
      Servings = servings;
    }
 
    public Builder Calories(int calories)
    { Calories = calories; return this; }
    ...
 
    public NutritionFacts Build()
    {
      return new NutritionFacts(this);
    }
  }
 
  private NuitritionFacts(Builder builder)
  {
    ServingSize = builder.ServingSize;
    Servings = builder.Servings;
    Calories = builder.Calories;
    ...
  }
}

If you try to compile that code, the C# compiler will complain, saying that it does not have permission to access the private members of the Builder class.

Then how come it worked in Java? The answer is that Java has a special rule that allows Java outer classes to access the private members of their inner classes. In C#, this rule does not exist, and thus C# outer classes cannot access the private members of C# inner classes.

Since Bloch’s Builder pattern doesn’t work in C#, the natural next question is: how do we make it work?

Approach 1: Make Builder Properties Public

The C# compiler tells us that it can’t compile because it doesn’t have permission to access private members of the nested Builder class. Thus, the most obvious solution to this is to make them public:

public class NutritionFacts
{ 
  ...
  public class Builder
  {
    public int ServingSize { get; set; }
    public int Servings { get; set; }
    public int Calories { get; set; }      
    ...
  }
  ...
}

This allows the code to compile, and we can use the Builder just as we used it in Java.

However there is one niggling concern: the C# Builder exposes getters in the Builder object. In the Java Builder, when we were constructing an object, we were only able to use methods that contributed to building the object. That is, the Java Builder doesn’t expose any getters. However, in the C# version, our API is polluted by unneeded getters. Let’s see if we can do better.

Approach 2: Build the object in the Builder

As we’ve already seen, C# does not permit outer classes to access the private members of inner classes. However, C# does let us access outer classes from inner classes. Since that’s the case, why don’t we invert the building procedure. That is, let’s build the object in the Builder, instead of in the class being built:

public class NutritionFacts
{
  public int ServingSize { get; private set; }
  public int Servings { get; private set; }
  public int Calories { get; private set; }
  ...
 
  public class Builder
  {    
    private int ServingSize { get; set; }
    private int Servings { get; set; }
    private int Calories { get; set; }
 
    public Builder(int servingSize, int servings)
    {
      ServingSize = servingSize;
      Servings = servings;
    }
 
    public Builder Calories(int calories)
    { Calories = calories; return this; }
    ...    
 
    public NutritionFacts Build()
    {
      return new NutritionFacts
      {
        ServingSize = ServingSize,
        Servings = Servings,
        Calories = Calories,
        ...       
      };
    }
  }
 
  private NuitritionFacts()
  { 
    // Intentionally empty.
  }
}

That, to me, is the closest you can get to the Java pattern. From an API consumer’s point of view, it’ll look identical to a Java Builder.

Alternative Form

There is another alternative to the two C# Builders mentioned earlier in this article. As it stands, Bloch’s Builder can be used as a sort of prototype factory. You can configure the builder and then pump out instances of the class that have that configuration. However, if you’re using the Builder to make a single, immutable instance, a more efficient way would be to avoid copying the data first to the Builder and then to the new instance.

Here’s a version of the Builder (by Jon Skeet) that can be used only once, but avoids unnecessary data copying.

public class NutritionFacts
{
  public int ServingSize { get; private set; }
  public int Servings { get; private set; }
  public int Calories { get; private set; }
  ...
 
  public class Builder
  {       
    private NutritionFacts _facts = new NutritionFacts();
 
    public Builder(int servingSize, int servings)
    {
      _facts.ServingSize = servingSize;
      _facts.Servings = servings;
    }
 
    public Builder Calories(int calories)
    { _facts.Calories = calories; return this; }
    ...    
 
    public NutritionFacts Build()
    {
      var ret = facts;
 
      // Invalidates builder to maintain mutability.
      facts = null;
 
      return ret;
    }
  }
 
  private NuitritionFacts()
  { 
    // Intentionally empty.
  }
}

Some of the advantages of this pattern are:

  • No data copying is required at build time. In other words, while you’re setting the properties, you’re doing so on the real object – you just can’t see it yet. This is similar to what StringBuilder does.
  • The builder becomes invalid after calling Build() to guarantee immutability. This unfortunately means it can’t be used as a sort of “prototype” in the way that Bloch’s version can.

Conclusion

In this article we’ve looked at 3 different working C# implementations of Bloch’s Builder pattern. The first approach was a quick and dirty fix that got the job done. The second approach applied a bit more finesse and managed to keep the same API as the Java Builder. The final approach was more of a variation on the second approach, offering a more efficient implementation of the pattern if you’re not using the Builder as an object prototype factory.

5 Comments so far

  1. Vili on July 4th, 2009

    Hi,

    I think you could write your public properties with just set; and you would have a write-only property

  2. DotNetShoutout on July 4th, 2009

    Cameron McKay » Joshua Bloch’s Builder Pattern in C#…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  3. cam on July 4th, 2009

    @Vili: Which approach are you talking about?

  4. Casper Bang on July 5th, 2009

    1) Bloch did not invent that pattern. It’s part of a whole arcade of patterns classified as “creational” and immortalized in the seminal book by the GoF in 87′.

    2) C# has property initializers, making the builder pattern somewhat unnecessary.

    3) The builder pattern is defined by method chaining, surely nothing stands in the way of using setCalories(…).build() in C#?

  5. cam on July 5th, 2009

    @Casper Bang:

    1) I never said Bloch invented the pattern. The reason I refer to it as Bloch’s Builder pattern is because his pattern isn’t exactly the same as the GoF pattern, and thus needs to be distinguished.

    2) I disagree with this point. Although property initializers make unnecessary some types of Builders, there are still things they can’t do. For example, you cannot create immutable objects with property initializers, but you can with a Builder.

    3) The Builder patterns in this article, as well as Bloch’s Java Builder, support chaining.

Leave a reply

ERROR: si-captcha.php plugin says GD image support not detected in PHP!

Contact your web host and ask them why GD image support is not enabled for PHP.

ERROR: si-captcha.php plugin says imagepng function not detected in PHP!

Contact your web host and ask them why imagepng function is not enabled for PHP.