Chainable Methods and the Fluent API
The concept of Fluent Interfaces was introduced in an workshop by Eric Evans and Martin Fowler, the gurus of Software Engineering, in 2005. The proposal was to create Object-Oriented APIs whose code would be easily read. That would require a technique called Method Chaining to implement it. In this article I will show an example on how to implement this approach, as well as its pros and cons. At the end of the day, you will understand which situation is the best to use or avoid.
The central idea is based on simplify the use of the objects, promoting a fluidity in writing the code. According to Fowler, the main reason to create a fluent API is to follow the same quality line of a Domain Specific Language (DSL). A DSL is a generic language which developers create to solve domain's specific issues, when there are communication and understanding problems regarding the complex business rules that the project may bring. I.e, if an API is well planned since its beginning, it will be possible to abstract the problem so that the communication of the domain be equivalent to the natural language.
It is possible to map a model, an algorithm, etc in a fluid expression. Please click on the links below to know more about DSLs.
What can make code writing fluid? According to the autors, by promoting multiple subsequent method calls to the same object instance we have a Method Chaining in a whole expression. Namely, to call a method you need an object that defines it first. Then, to guarantee the chaining, each method must return a reference to the object that created it (this). The last method should not return "this".
I created a sample application to contextualize. Suppose we have a flight and want to know its data (flight number, origin, destination, date, and duration).
public
class
Flight
{
``string
_origin;
``string
_destination;
``DateTime _date;
``public
int
FlightID {
get``; ``private
set``; }
``public
Flight(``int
id) { ``this``.FlightID = id; }
``public
static
Flight CreateFlight(``int
id)
``{
``return
new
Flight(id);
``}
``public
Flight Origin(``string
origin)
``{
``this``._origin = origin;
``return
this``;
``}
``public
Flight Destination(``string
destination)
``{
``this``._destination = destination;
``return
this``;
``}
``public
Flight When(DateTime date)
``{
``this``._date = date;
``return
this``;
``}
``public
int
Duration(``int
hours)
``{
``return
hours;
``}
}
/* Flight Data
``* Flight Number: 1234
``* Origin: SP (São Paulo)
``* Destination: RJ (Rio de Janeiro)
``* Date: Today
``* Duration: 1h
``*/
Flight.CreateFlight(1234).Origin(``"SP"``).Destination(``"RJ"``).When(DateTime.Today).Duration(1);
The cons of this approach. A chained expression makes it impossible to debug. Besides taking longer to code, it is not always that their methods and classes are adaptable (unless you create an API from scratch with this in mind). A constructor-based API with properties and additional methods is easier to write. This development way states that it does not make sense for a setter to return a value.
You should not create and API thinking about help the developer's work, because he/she will find more complex in a means of writing more code lines. Therefore, this metodology provides simplified interfaces to method calls. In some cases it turns out to be really necessary, as in unit testing or mocks to validate business rules. Also, to validate domain concepts with stakeholders. Two examples of fluent APIs are LINQ and NHibernate.
Links:
Fluent Interface - Martin Fowler
Domain Specific Language - About
Domain Specific Language - Example
See ya,
Thiago