Inside Paulo Abrantes' head
[ start | index | login or register ]
start > 2007-11-14 > 1

Software Developing: Fluent Interfaces

Created by pabrantes. Last edited by pabrantes, 234 days ago. Viewed 602 times. #4
[diff] [history] [edit] [rdf]
labels
attachments
fluent-flowchart-small.png (27604)
fluent-flowchart.png (31930)
proxy-uml.png (21322)

Software Developing: Fluent Interfaces

Lately I've seen various blogs mentioning Fluent Interfaces. Being a >>Martin Fowler's "fan" I already had read about the concept. As expected, using it implies decisions and trade-offs, this post will not only explain what a fluent interface is but also present the trade-offs and suggest possible implementations.

I'll start by introducing the concept.

Fluent Interface: The concept

The idea is quite simple, an object's interface is said to be fluent when any method invocation available in the interface allows the developer to chain other method invocations, making the code design "flow".
This property is sometimes called chainability (like in >>jquery), although >>Martin Fowler and >>Eric Evans coined the term fluent interface.

A good way to clarify the concept is by using an example.
Let's imagine the following scenario: there's an object - called QueryObject - that allows search terms (criteria) to be added and execute a query.

A possible implementation using a non-fluent interface could be:

public class QueryObject { private List<String> criterias;

public Queryobject() { criterias = new ArrayList<String>(); }

public void withCriteria(String criteria) { criterias.add(criteria); }

public List<QueryObjectResult> execute() { //.... some code here } }

Using such object results in the following:

QueryObject query = new QueryObject(); query.withCriteria("criteria 1"); query.withCriteria("criteria 2"); query.withCriteria("criteria 3"); List<QueryObjectResult> results = query.query();

On the other hand a fluent interface for query object would look like:

public class QueryObject { private List<String> criterias;

public Queryobject() { criterias = new ArrayList<String>(); }

public QueryObject withCriteria(String criteria) { criterias.add(criteria); return this; }

public List<QueryObjectResult> execute() { //.... some code here } }

Should be noticed that the method addCriteria was renamed to withCriteria and instead of returning void returns itself. The first modification (name modification) is irrelevant, but the second one (return type modification) it's what allows calling fluent to the object's interface.

Using this object would result in the following code:

QueryObject query = new QueryObject(); List<QueryObjectResult> results = query.withCriteria("criteria 1").withCriteria("criteria 2").withCriteria("criteria 3").execute();

With the previous example, fluent interfaces may look interesting but, not that useful.
In my opinion, fluent interfaces are truly helpful when designing custom >>Domain Specific Languages (DSL). Allowing the DSL keywords to chain with each-other can, when well designed, create instructions really close to natural language.
A good example of a well achieved DSL with fluent interface is >>JMock's test definitions. Here's an example taken out of >>jMock: Yoga for Your Unit Tests:

// [..snipped code..] logger.expects(once()).method("setLoggingLevel").with(eq(Logger.WARNING)) .id("warning level set"); logger.expects(once()).method("warn").with(warningMessage) .after("warning level set"); // [..snipped code..]

The previous code, in my opinion, has excellent readability which improves the code quality.

But, like I said before, there are trade-offs. One of the obvious trade-offs is the violation of the Command and Query Separation principle.
The Command and Query principle states that object methods should be divided in two categories: queries, where a result is returned and the object state isn't change and commands, where no result is returned and the object state is changed.
Having a setter or an adder (hence, command methods) that returns the object itself goes against the principle. This also means that fluent interface aren't compatible with the JavaBean's setter, getter convention.

Another trade-off is the complexity of designing these interfaces. A developer new to fluent interfaces might take a while until (s)he starts developing good fluent interfaces.
It may take extra effort to develop such interfaces, but - as already seen in the JMock example - it greatly improves software's design.

Fluent Interfaces: Implementation

There are various ways of implementing fluent interface, but one thing is certain, implementation should always be done in a non-intrusive way. Non-intrusive way should be understood as keeping "old" behaviour untouched and add fluent behaviour.
This can be done in different ways, I'll be discussing two different approaches: using inner classes and using proxies.

Using an Inner Class

fluent-flowchart-small

One of the simplest ways for creating a fluent interface is creating an inner class and then have methods to start (in the object) and finish (in the "fluent object") the fluent process. The inner class can be directly inside the class which will be receiving the fluent interface or if it's impossible to modify it, through hierarchy.

The idea is that at a given moment the developer decides to use the fluent interface by calling the start method. After that call, methods can be chained and then at the end of the chain another object can be returned or the same object from the beginning of the process, but in the non-fluent way.

The flowchart for the inner class' behaviour can be seen in the picture at the right.

The main advantage of this method is that it's quite simple to implement and doesn't necessarily need the creation of new public classes and interfaces that might contribute for an explosion of classes.
On the other hand the creation of such inner classes and their maintenance can be a huge and tedious task.

Probably a good scenario to use such implementation would be in an environment where a domain language would be used to define the application's domain classes and generating them through a code generator. That generator would create the classes and, for the ones who would be configured to allow fluent interfaces, the inner class.

Show source code
public class YetAnotherPOJO { private String someString; private Integer someInteger; private FluentYetAnotherPOJO fluentInterface;

public void setSomeString(String string) { this.someString = string; }

public String getSometString() { return this.someString; }

public void setSomeInteger(Integet integer) { this.someInteger = integer; }

public Integer getSomeInteger() { return this.someInteger; }

public FluentYetAnotherPOJO start() { if(fluentInterface == null) { fluentInterface = new FluentYetAnotherPOJO(); } return fluentInterface; }

private class FluentYetAnotherPOJO {

public FluentYetAnotherPOJO setSomeString(String string) { YetAnotherPOJO.this.setSomeString(string); return this; }

public FluentYetAnotherPOJO setSomeInteger(Integer integer) { YetAnotherPOJO.this.setSomeInteger(integer); return this; }

public String getSomeString() { return YetAnotherPOJO.this.getSomeString(); }

public Integer getSomeInteger() { return YetAnotherPOJO.this.getSomeInteger(); }

public YetAnotherPOJO finish() { return YetAnotherPOJO.this; } } }

Using a Proxy

Another way to implement fluent interfaces is by using proxies. The basic idea is to create a custom implementation handler that will use an interface that specifies a fluent interface and a certain object, linking them together through a convention. Anyone interested in reading about how Java proxies work, should read >>Java Programming: Proxies and References Java Programming: References' Package where I explain in detail what is a proxy, an implementation handler and the mechanism of Java proxies.

proxy-uml

The idea used in this approach is simple:

  • First there is an interface that represents a fluent interface containing every method needed, with a minor detail the setterMethods instead of being named setSomethig will be called something and will returns the interface itself (this avoids conflicts with the setter convention).
  • Then there is a custom implementation handler which always contains the object being proxied. When a method is called if its name isn't finish nor starts with get then, the handler tries to find a method named "set" suffixed by the name of the method invoked in the object being proxied and if found invoke it. Finally, after invocation returns itself.
I could provide some example source code, but >>Stephan Schmidt already wrote an excellent post talking about this idea called >> Fluent Interface and Reflection for Object building in Java, anyone interested in seeing the Java's source code for this implementation should also read his post.

The main advantages of using this approach is that there's only one class implementing the fluent interface behaviour, which is the custom implementation handler. Although, since this approach uses proxies, one interface will be needed for each desired fluent interface. This leads to what I've been calling an interface explosion which, in my opinion, is bad design.

Conclusions

Fluent Interfaces seem to be a good way to improve software design, specially if there are DSLs involved, but beware, they should be used with caution. In order to achieve a good and useful fluent interface the developer needs to already have knowledge about the applications' domain and how operations can and should be chained.
Another thing that must be kept in mind while working with fluent interfaces is that they violate the Command Query Separation principle, hence, may have conflicts with the getter, setter convention, which could lead to some problems.

2 comments (by m4ktub, pabrantes) | post comment
Who am I?
paulo-roca2My name is Paulo Abrantes AKA pabrantes and I'm a software developer. I'm currently employed at >>CIIST working as a Java developer in >>FenixEDU.

This blog is mostly about Java programming, domain driven design and snipsnap bliki developing. Everything written in this blog is my personal opinion and it may not reflect the opinions of my employer and co-workers.


Blog subscription
subscribe by rss subscribe by email

Links
>> Home
>> Paulo's Profile
>> Post History
>> Add to Technorati Favorites
>> Paulo's Photo Gallery
>> WishList
>> Posting without Login

Search Blog
Fellow Bloggers

Recent Posts

Java Programming: Bytecode Injection
Intermission: Sorry For Downtime
Software Developing: Studying The Bliki Domain Model
SnipSnap Developing: Trying to settle a roadmap
System Administration: Load Balancing with Apache
Blogging: Two years have passed
Software Developing: The SnipSnap Saga
Java Programming: Getting your code spicy with Groovy
Software Developing: Fluent Interfaces
Software Developing: Implementing a ShoutBox on SnipsSnip
Software Developing: SnipSnap, SnipIt and SnipSnip
Java Programming: Proxies and Access Control
Java Programming: Proxies and References
Java Programming: References' Package
YALM: Yet Another Layout Modification

For older posts, please refer to post-history for a complete Post History

Logged in Users: (0)
… and 19 Guests.
This is a modified version of snipsnap.org created by >>Paulo Abrantes