April 9, 2012

Conditional Builder Design Pattern

Have you ever wanted to use the Builder design pattern to create a really cool fluent interface for building objects but you wanted to add conditions to the building? The good news is that you can do something like so:

var level = new Random().Next(1, 20);
var ninjaBuilder = NinjaBuilder
.CreateNinjaBuilder()
.AtLevel(level)
.WithShurikens(10)
.WithSkill("hideinshadows")
.When(() => level > 5);
var ninja = ninjaBuilder.Build();
view raw gistfile1.cs hosted with ❤ by GitHub

Notice how in this contrived example a ninja only gets the "hide in shadows" skill after reaching 6th level? To handle a conditional builder take a look at the following code:

public class NinjaBuilder
{
private readonly List<Action<Ninja>> _builderActions;
public static NinjaBuilder CreateNinjaBuilder()
{
return new NinjaBuilder();
}
public NinjaBuilder()
{
_builderActions = new List<Action<Ninja>>();
}
public NinjaBuilder AtLevel(int level)
{
_builderActions.Add(n => n.Level = level);
return this;
}
public NinjaBuilder WithShurikens(int numShirukens)
{
_builderActions.Add(n => n.Shirukens = numShirukens);
return this;
}
public NinjaBuilder WithSkill(string skill)
{
_builderActions.Add(s => s.Skill = skill);
return this;
}
public NinjaBuilder When(Func<Boolean> condition)
{
var result = condition.Invoke();
if (!result)
{
var oldAction = _builderActions[_builderActions.Count - 1];
_builderActions.Remove(oldAction);
}
return this;
}
public Ninja Build()
{
var ninja = new Ninja();
_builderActions.ForEach(ba => ba(ninja));
return ninja;
}
view raw gistfile1.cs hosted with ❤ by GitHub
For a complete sample project check it out on my GitHub account!