Mr Andersson

Posts Tagged ‘ood

A fluent interface and the Builder pattern

leave a comment »

My former collegue Thomas Lundström blogged about fluent interfaces quite a while ago, which he followed up in a comment to Johan Lindfors’ post “A small DSL to order coffee” (in Swedish).

The blog post and its comments discusses two different approaches to fluent interfaces. The first approach is based on getters which mutates the instance when they are called. Some people think this is a very bad design – getters should not mutate the instance!
I agree on that. I strongly believe that a get operation should be idempotent and not mutate the object instance. This for the same reason a HTTP GET request should not mutate a resource and a HTTP POST/PUT should mutate a collection/the resource.
(That’s why I prefer RESTful web services more than SOAP over HTTP, but that’s a totally different blog post. 🙂

The second approach is the one that Thomas points out. It’s the classical Builder Pattern where you have a totally separate class which is used to build object instances. It differentiates itself among the creational OOD design patterns by targeting primarily mutable objects. It’s like a bunch of Factory methods which is used like a Factory, but instead of having thousands of different methods in one Factory (overloads for example), the Builder is used in several calls to create/configure the final object instance.

An approach which was recently used at work is a mix of the two approaches mentioned above. Instead of having a separate builder we have builder methods on the object instance itself, either directly or via extension methods. Separate from the builder methods we got some Factory Methods. These are the starting point to create a basic instance. The builder methods are then used to further shape the object instance to our needs.

Approach #1 – getters which creates/mutate the object instace:


Coffee myLatte = Coffee.OrderLatte.Double.FatFree.Vanilla;

Approach #2 – a separate builder


Coffee myLatte = CoffeeBuilder.Latte().Double().FatFree().Vanilla().Build();

Our approach – a mix of factory methods and builder methods on the object instance itself


Coffee myLatte = Coffee.Latte().Double().FatFree().Vanilla();

So what’s the pros and cons with the last two approaches?
I guess they are quite similar, but here is some pros:
– The separate builder seems a bit more aligned with the Separation Of Concerns principle
– The built-in builder methods via extension methods provides a lightweight class structure, even for classes in a third-party class library, such as the BCL.

(Please post a comment if you can think of more pros and cons or if you just totally disagree with me 🙂

So of course, the $10.000 question answer is… It depends on your context!
Anyhow, here is a sample how we tend to use this mix of Factory Methods and Builder methods at work.

The following code is used to build construct the collection of DataGridViewColumns used in a Windows Forms DataGridView control.
The CreateColumns() method is used to create an enumeration of the columns to use and TextColumn() is a sample Factory Method.


protected override IEnumerable CreateColumns()
{
yield return TextColumn()
.For( WorkOrderPresenter.Properties.Title )
.WeightedWidth( 100 );

yield return TextColumn()
.For( WorkOrderPresenter.Properties.Description )
.WeightedWidth( 200 );

yield return ComboBoxColumn( _activityBindingSource )
.For( WorkOrderPresenter.Properties.Activity )
.WeightedWidth( 100 )
.Width( 90, 130 );
....
}

///
/// Creates a textbox column with default behavior.
///

protected virtual DataGridViewTextBoxColumn TextColumn()
{
return new DataGridViewTextBoxColumn().WrapContents().WithDefaultBehavior();
}

The methods For(), WeightedWidth(), Width(), WrapContents() and WithDefaultBehavior() are Builder (extension) methods on DataGridViewColumn.

Advertisements

Written by anderssonjohan

March 12, 2009 at 18:03