Last year, I blogged about Test Data Builders here and here. I still use them heavily in my unit tests for creating objects with test data. Heck, I also use this pattern for fluent interfaces in production code. Here is a simple example of this approach:
public class CustomerBuilder
{
public String _firstName = "Homer";
public String _lastName = "Simpson";
public CustomerBuilder WithFirstName(String firstName)
{
_firstName = firstName;
return this;
}
public CustomerBuilder WithLastName(String lastName)
{
_lastName = lastName;
return this;
}
public Customer Build()
{
return new Customer(_firstName, _lastName);
}
}
This fluent builder class can then be used this way:
Customer customer = new CustomerBuilder()
.WithFirstName("Homer")
.WithLastName("Simpson")
.Build();
A while ago, Greg Young started a series of blog posts on DDDD (Distributed Domain-Driven Design), which I can highly recommend. Make sure to catch up now you still can because I think that he has a lot of stuff coming up, which I'm really looking forward to.
Anyhow, Greg had a couple of posts on fluent builders, which you can read here, here and here. I noticed an interesting approach in the way that the target object is built. Here is an example of this approach:
public class CustomerBuilder
{
public String _firstName = "Homer";
public String _lastName = "Simpson";
public CustomerBuilder WithFirstName(String firstName)
{
_firstName = firstName;
return this;
}
public CustomerBuilder WithLastName(String lastName)
{
_lastName = lastName;
return this;
}
public Customer Build()
{
return new Customer(_firstName, _lastName);
}
public static implicit operator Customer(
CustomerBuilder builder)
{
return builder.Build()
}
}
which results in the following usage:
Customer customer = new CustomerBuilder()
.WithFirstName("Homer")
.WithLastName("Simpson");
Adding an implicit cast operator to the builder class makes that its no longer required to explicitly call the Build method. I keep the Build method around for backwards-compatibility reasons or in case I ever need it again (violating YAGNI in the process, I know, I know). I find that adding the implicit cast operator adds to the readability of the fluent interface, don't you agree?