Wednesday, February 01, 2006

Using Fluent Interface

While working on .norm I needed to create a class that could be used to specify criteria. Specifically, I needed a class that represented a SQL where clause.

I considered using a comparison object array, but this would only allow for "and" comparisons (and would exclude "or"). I finally decided that it was important to maintain the order of the comparison objects in some way. I decided on a builder. The builder would produce a string based on the order that the user added "and" or "or" comparisons.

Then, I recently read Martin Fowler's bliki entry, fluent interface, and it seemed a better fit.

In the 0.1 version of .norm the WhereBuilder class can be used like the example from .norm update usage. However, the in the next version, where usage would look more like a fluent interface. A where clause with one equal comparison will look like:
IWhere where = new Where().Column("foo").IsEqualTo("bar");

A where clause with 2 equal comparisons will look like:
IWhere where = new Where().Column("foo").IsEqualTo(0).And.Column("bar").IsEqualTo(1);

The new implementation is more verbose than the previous version of WhereBuilder. But, I think it is valuable because it better conveys what the code is accomplishing.

The most interesting thing I learned while developing the interface was how to guard against improper usage. For example, users should include the And property instead of skipping it. Therefore, some type of state in the object must be kept that determines what the next expected method (or property) call will be. If the next method called is not the expected call, an exception is thrown specifying which method call was expected.

Requiring the users to use the fluent interface correctly is important because much of the value of fluent interface is in conveying a message in the code. If the interface isn't used in a fluent manner than there's no point in creating the fluent interface.
Post a Comment