Fluency in Fluent Interfaces

Scott Hanselman's recent post about the Daily Source Code 14 - Fluent Interface Edition got me to think more on fluent interfaces and a previous post of mine on ObjectMother versus Test Data Builders.  Also, it comes to mind in regards to DSLs, both internal and external that has me intrigued.  Partially due to my latest involvement with Ruby and F#.

Test Data Builder Example

So, let's revisit that simple example:

public class ClaimBuilder
{
     private DateTime claimDate;
     private Provider provider = ProviderBuilder.StartRecording().Build();
     private Recipient recipient = RecipientBuilder.StartRecording().Build();
     private ClaimLineCollection claimLines = ClaimLinesBuilder.StartRecording.Build();

     public static ClaimBuilder StartRecording()
     {
          return new ClaimBuilder();
     }

     public ClaimBuilder WithClaimDate(DateTime claimDate)
     {
          this.claimDate = claimDate;
          return this;
     }
    
     public ClaimBuilder WithProvider(Provider provider)
     {
          this.provider = provider;
          return this;
     }

     public ClaimBuilder WithRecipient(Recipient recipient)
     {
          this.recipient = recipient;
          return this;
     }

     public ClaimBuilder WithClaimLines(ClaimLineCollection claimLines)
     {
          this.claimLines = claimLines;
          return this;
     }

     public static implicit operator Claim(ClaimBuilder builder)
     {
          return new Claim(builder.claimDate, builder.provider, builder.recipient, builder.claimLines);
     }
}

As you may note I changed the Build method from the previous post to an implicit operator to save me some coding time when it comes to my builders.  This is one of the very very few places where I'd recommend using this operator.  Anyhow, then we'd have the calling code to look similar to this for my unit tests.

Claim claim = ClaimBuilder.StartRecording()
     .WithClaimDate(new DateTime(2008, 1, 1))
     .WithProvider(ProviderBuilder.StartRecording()
          .WithName("Robert", "Jones")
          .WithAddress(AddressBuilder.StartRecording()
               .WithStreetAddress("1800 28th St, NW")
               .WithCity("Washington")
               .WithState("DC"))))
     .WithRecipient(RecipientBuilder.StartRecording()
          .WithName(James", "Smith")
          .WithAddress(AddressBuilder.StartRecording()
               .WithStreetAddress("1210 14th St, SE",)
               .WithCity("Washington")
               .WithState("DC"))))
     .WithClaimLines(ClaimLinesBuilder.StartRecording()
          .WithClaim("00308-1")));

This is truly powerful here to make it make sense to the reader instead of the usual black box ObjectMother approach.  When building my entity objects for test, this is the main approach I use. 

Other Examples

Scott Bellware has introduced the Behavior Driven Development NUnit Extensions which makes heavy use of fluent interfaces.  With my deeper dive into BDD, this has been very helpful.  Dave Laribee also has me on the kick as well, so lots of thanks to them for pointing me in the right direction, although some may disagree with their directions.  But that's for another time and another post.

Jeremy Miller also has fluent interfaces on his StructureMap IOC container project.   Some new parts with registration will be coming up with his new release of version 2.5 as noted here.

Of course I can keep rattling on with others like NHibernate and the ICriteria, Castle Windsor's fluent registration interfaces and so on.  The list goes on!  Very cool stuff coming out lately...  Until next time!

kick it on DotNetKicks.com

2 Comments

  • Hi Matthew,

    LinFu's DBC also supports fluent interfaces in creating dynamic
    contracts. Here's an example:

    // ...
    Ensure.On(contract)
    .ForMethodWith(givenName)
    .That(isConnected)
    .And
    .ReturnValueIs(notNull)
    .And
    .ThatProperty("SomeProperty")
    .ComparedToOldValue
    .ShouldBe(propertyCondition)
    .OtherwisePrint("Postcondition failed!");

  • Phillip,

    Very cool and so noted! I'm still looking at the LinFu libraries and it's pretty interesting stuff.

    Matt

Comments have been disabled for this content.