Fluent Builder Pattern for classes with long-ish constructors

Spread the love

Last week I discovered a rather wonderful construct for objects with long constructors, e.g. immutable value types:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserProfile
{
    public string City { getprotected set; }
    public string Country { getprotected set; }
    public Uri Url { getprotected set; }
    public string Email { getprotected set; }
    public string Tagline { getprotected set; }
    public UserProfile(string city, string country, Uri url, string email,
        string tagline)
    {
        ...
    }
}

This constructor has bad Connascence of Position (CoP); to construct a UserProfile instance, users have to know the position of each parameter. Otherwise they might mix up the city with the country for example:

1
2
3
// Spot the bug!
var profile = new UserProfile("NZ""Wellington",
    new Uri("http://richarddingwall.name"), "rdingwall@gmail.com"".NET guy");

This won’t be a problem with named parameters in C# 4.0, but until then, a nice alternative is a fluent builder class as described:

1
2
3
4
5
6
UserProfile profile = new UserProfileBuilder()
    .WithCity("Wellington")
    .WithCountry("NZ")
    .WithUrl(new Uri("http://richarddingwall.name"))
    .WithEmail("rdingwall@gmail.com")
    .WithTagline(".NET guy");

Builders are very easy to implement. Each With method records its value and returns the current builder instance. Then we provide an implicit cast operator that finally constructs a UserProfile with all the parameters in the right places.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserProfileBuilder
{
    internal string City { getset; }
    internal string Country { getset; }
    // ... etc
    public UserProfileBuilder WithCity(string city)
    {
        this.City = city;
        return this;
    }
    // ... etc
    public static implicit operator UserProfile(UserProfileBuilder builder)
    {
        return new UserProfile(builder.City, builder.Country, builder.Url,
            builder.Email, builder.Tagline);
    }
}

I really like this!

Leave a Reply

Your email address will not be published. Required fields are marked *