A Fluent Builder in C#

When it comes to the number of arguments to pass to a function, Uncle Bob is pretty clear. Quoting from Clean Code:

The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided when possible. More than three (polyadic) requires very special justification – and then shouldn’t be used anyway.

Still, some objects might have more than 3 attributes or properties and you usually need some way to initialize them via the constructor. Some attribute might not be mandatory, therefore on some occasions you can get by with a few overloads adding more parameters as needed.

Consider the following (contrieved) example from the world of soccer. I have picked a few attributes that encapsulate the concept of a Team.

namespace Soccer
{
    public enum Color
    {
        White,
        Red,
        Green,
        Blue
    }

    public class Team
    {
        string Name { get; set; }
        string NickName { get; set; }
        Color ShirtColor { get; set; }
        string HomeTown { get; set; }
        string Ground { get; set; }

        public Team(
            string name,
            string nickName,
            Color shirtColor,
            string homeTown,
            string ground)
        {
            Name = name;
            NickName = nickName;
            ShirtColor = shirtColor;
            HomeTown = homeTown;
            Ground = ground;
        }
    }
}

Let’s try initializing one team:

Team team1 = new Team(
    "Manchester United",
    "The Red Devils",
    Color.Red,
    "Manchester",
    "Old Trafford");

In this case we are passing 5 arguments into the constructor. Consider that most of the parameters is a string, therefore it’s quite easy to get confused and invert the order of some parameter (the first two or the last two). The compiler would not be able to help in this case.

What may help here is a builder object with a fluent interface which can help specifying all the attributes of the team. Something like the following:

TeamBuilder tb = new TeamBuilder();
Team team2 =
    tb.CreateTeam("Real Madrid")
        .WithNickName("Los Merengues")
        .WithShirtColor(Color.White)
        .FromTown("Madrid")
        .PlayingAt("Santiago Bernabeu")
        .Build();

Let’s see the code for the TeamBuilder class:

public class TeamBuilder
{
    private string name;
    private string nickName;
    private Color shirtColor;
    private string homeTown;
    private string ground;

    public TeamBuilder CreateTeam(string name)
    {
        this.name = name;
        return this;
    }

    public TeamBuilder WithNickName(string nickName)
    {
        this.nickName = nickName;
        return this;
    }

    public TeamBuilder WithShirtColor(Color shirtColor)
    {
        this.shirtColor = shirtColor;
        return this;
    }

    public TeamBuilder FromTown(string homeTown)
    {
        this.homeTown = homeTown;
        return this;
    }

    public TeamBuilder PlayingAt(string ground)
    {
        this.ground = ground;
        return this;
    }

    public Team Build()
    {
        return new Team(name, nickName, shirtColor, homeTown, ground);
    }
}

The only catch in the solution above is that the caller needs to call Build() at the end of the call chain.

We can improve the solution using an implicit user-defined type conversion operator:

public class TeamBuilder
{
    private string name;
    private string nickName;
    private Color shirtColor;
    private string homeTown;
    private string ground;

    public TeamBuilder CreateTeam(string name)
    {
        this.name = name;
        return this;
    }

    public TeamBuilder WithNickName(string nickName)
    {
        this.nickName = nickName;
        return this;
    }

    public TeamBuilder WithShirtColor(Color shirtColor)
    {
        this.shirtColor = shirtColor;
        return this;
    }

    public TeamBuilder FromTown(string homeTown)
    {
        this.homeTown = homeTown;
        return this;
    }

    public TeamBuilder PlayingAt(string ground)
    {
        this.ground = ground;
        return this;
    }

    // CONVERSION OPERATOR
    public static implicit operator Team(TeamBuilder tb)
    {
        return new Team(
            tb.name, 
            tb.nickName, 
            tb.shirtColor, 
            tb.homeTown, 
            tb.ground);
    }

This allows you to create new teams in a more natural way as follows:

TeamBuilder tb = new TeamBuilder();

Team team3 = tb.CreateTeam("Chelsea")
    .WithNickName("The blues")
    .WithShirtColor(Color.Blue)
    .FromTown("London")
    .PlayingAt("Stamford Bridge");

The above solution, albeit quite simple, is a good starting point. To make it ready for real-world code, you should making it more robust with some error checking (what happens if I omit some call from the chain? If I pass an invalid argument? Etc…).

More, you might want to hide the actual implementation from the clients and extract an interface or abstract class from the concrete TeamBuilder. This is left to the reader as an excercise :)

kick it on DotNetKicks.com


Shout it

This entry was posted in .NET, C# and tagged , . Bookmark the permalink.
  • Pingback: DotNetShoutout

  • P

    interesting – however, I think fluent interface is optimally suited for queries rather than constructors:

    e.g. Query.createQuery().andName(“Chelsea”).list();

    The drawback I see with the solution you are proposing is that TeamBuilder, if used without implicit user-defined type conversion operator, which AFAIK is unavailable in other languages such as Java, replicates all attributes of Team, which in turn could cause maintainability issues.

    Could TeamBuilder subclass Team to actually avoid this? It would also have the advantage of permitting a private constructor for both Team and TeamBuilder…

  • P

    interesting – however, I think fluent interface is optimally suited for queries rather than constructors:

    e.g. Query.createQuery().andName(“Chelsea”).list();

    The drawback I see with the solution you are proposing is that TeamBuilder, if used without implicit user-defined type conversion operator, which AFAIK is unavailable in other languages such as Java, replicates all attributes of Team, which in turn could cause maintainability issues.

    Could TeamBuilder subclass Team to actually avoid this? It would also have the advantage of permitting a private constructor for both Team and TeamBuilder…

  • stefanoricciardi

    P,

    thank you for stepping by and leaving a comment.

    The way I see it, a creational pattern such as the builder is always going to be somehow coupled to the object(s) it’s creating. The goal of creational patterns make clients more independent on how an object is composed.

    The example that I have shown here is admittedly very simple. I have some implementations of this pattern where all the clients see is an interface (think of ITeamBuilder) which builds object implementing an interface (think ITeam).

    In such a scenario, I can make both concrete ITeamBuilder and ITeam implementations invisible to the clients (e.g. by marking the classes and their constructor as internal). This is serving well for me to decouple the clients from the actual implementation.

  • stefanoricciardi

    P,

    thank you for stepping by and leaving a comment.

    The way I see it, a creational pattern such as the builder is always going to be somehow coupled to the object(s) it’s creating. The goal of creational patterns make clients more independent on how an object is composed.

    The example that I have shown here is admittedly very simple. I have some implementations of this pattern where all the clients see is an interface (think of ITeamBuilder) which builds object implementing an interface (think ITeam).

    In such a scenario, I can make both concrete ITeamBuilder and ITeam implementations invisible to the clients (e.g. by marking the classes and their constructor as internal). This is serving well for me to decouple the clients from the actual implementation.

  • Dave

    Just an idea: what do you think about making CreateTeam a static method? This would allow the client to eliminate writing the construction code:

    var myTeam = TeamBuilder.CreateTeam(“Chelsea”)
    .WithNickName(“The blues”)
    .WithShirtColor(Color.Blue)
    .FromTown(“London”)
    .PlayingAt(“Stamford Bridge”);

    As I think about this though, I realize this would make it difficult to abstract TeamBuilder to the ITeamBuilder interface; so there is a tradeoff.

  • Dave

    Just an idea: what do you think about making CreateTeam a static method? This would allow the client to eliminate writing the construction code:

    var myTeam = TeamBuilder.CreateTeam(“Chelsea”)
    .WithNickName(“The blues”)
    .WithShirtColor(Color.Blue)
    .FromTown(“London”)
    .PlayingAt(“Stamford Bridge”);

    As I think about this though, I realize this would make it difficult to abstract TeamBuilder to the ITeamBuilder interface; so there is a tradeoff.

  • stefanoricciardi

    Dave,

    yes creating a static method can make sense (and I have seen other similar implementations resorting to static methods).

    However, as you correctly noted, my approach is to use the builder through an interface which rules out static methods. I might post some more on this.

  • stefanoricciardi

    Dave,

    yes creating a static method can make sense (and I have seen other similar implementations resorting to static methods).

    However, as you correctly noted, my approach is to use the builder through an interface which rules out static methods. I might post some more on this.

  • http://www.dobox.com/ Bruce

    Dave,

    yes creating a static method can make sense (and I have seen other similar implementations resorting to static methods).

    However, as you correctly noted, my approach is to use the builder through an interface which rules out static methods. I might post some more on this.

  • http://www.dobox.com/ Bruce

    Dave,

    yes creating a static method can make sense (and I have seen other similar implementations resorting to static methods).

    However, as you correctly noted, my approach is to use the builder through an interface which rules out static methods. I might post some more on this.

  • http://www.facebook.com/people/Eugene-ivanov/100002315795703 Eugene ivanov

    very nice

  • Peter Hardy

    The job of a constructor is ensure that objects are created in a valid state. What constitutes valid state is determined by the business domain not the compiler. Because of the default constructor, a fluent builder would allow us to create objects that are not in a valid state.

  • stefanoricciardi

    True. But the case being presented here has no behavior and/or state at all. It is just a bunch of properties, most of which happen to be strings.

    However, nothing prevents you to create a more sophisticated builder that does not expose all the properties of the object. Indeed each fluent step might even guide you in the creation process, removing options that would not be legitimate due to early choices made in the construction chain.