Conditional Builder Method Chaining Fluent Interface

builder, c#, design-patterns, fluent-interface, method-chaining

Solution

What I'd do is have `NinjaBuilder` keep the operations as a list of delegates, rather than applying them, and only apply them when `.Build` is called. This would allow you to make them conditional:

public class NinjaBuilder { 
    List<Action<Ninja>> builderActions = new List<Action<Ninja>>();

    public Ninja Build() {
        var ninja = new Ninja();
        builderActions.ForEach(ba => ba(ninja));
        return ninja;
    }

    public NinjaBuilder WithShurikens(int numShirukens) {
        builderActions.Add(n=>n.Shirukens = numShirukens);
        return this;
    }

    public NinjaBuilder When(Boolean condition) {
        if (!condition) // If the condition is not met, remove the last action
            builderActions.RemoveAt(builderActions.Length - 1);
        return this;
    }
}

Of course, this assumes that the condition is constant at the time of builder creation. If you want to make it non-constant, you could do something like this instead:

    public NinjaBuilder When(Func<Boolean> condition) {
        var oldAction = builderActions[builderActions.Length - 1];
        builderActions[builderActions.Length - 1] = n => { if (condition()) { oldAction(n); } }
        return this;
    }

If you want `When` be somewhat more compiler checked, you can make builderActions protected and do something like this:

public class ConditionalNinjaBuilder : NinjaBuilder {
    public ConditionalNinjaBuilder(NinjaBuilder wrappedBuilder) {            
        // Since someone might call .WithShirukens on the wrapping
        // builder directly, we should make sure that our actions 
        // list is the same instance as the one in our wrapped builder
        builderActions = wrappedBuilder.builderActions;
    }

    public ConditionalNinjaBuilder When(Func<Boolean> condition) {
        var oldAction = builderActions[builderActions.Length - 1];
        builderActions[builderActions.Length - 1] = n => { if (condition()) { oldAction(n); } }
        return this;
    }
}

and have the original operations return a ConditionalNinjaBuilder:

    public ConditionalNinjaBuilder WithShurikens(int numShirukens) {
        builderActions.Add(n=>n.Shirukens = numShirukens);
        return new ConditionalNinjaBuilder(this);
    }

That way you can only call `.When` after first calling another method. This has the additional advantage/complication of potentially allowing for nested/compounded conditionals, too. Yikes.

Problem

I was wondering what would be the best way to implement a `.When` condition in a fluent interface using method chaining in a `Builder` object? For instance how would I implement the `.WithSkill()` and `.When()` methods in the following example: ``` var level = 5; var ninja = NinjaBuilder .CreateNinja() .Named("Ninja Boy") .AtLevel(level) .WithShurikens(10) .WithSkill(Skill.HideInShadows) .When(level > 3) .Build() ``` Update - A sample solution can be found here.

Original source