Apr 11 2009

Reinventing the wheel: the fluent interface design pattern

Category: UncategorizedAleksander Kmetec @ 4:56 pm

What’s the fluent interface design pattern? It’s a design pattern which became very visible in recent time, mainly due to jQuery, which was designed around it. In this pattern, class methods return the same object they were called on (they end with “return this;”), which makes it possible to chain them. It also makes it easily spottable in code, due to the distinctive outline created by chained methods.

Let’s have a quick look at what I’m talking about.

If Java Swing libraries supported this kind of coding, then the following block of java code, copied from a random blog post, could be rewritten from this repetitive sequence:


JFrame mainFrame = new JFrame("Hello World");
mainFrame.add(label, BorderLayout.CENTER);
mainFrame.addWindowListener(new MainFrameListener());
mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);

…to this chain of methods:


new JFrame("Hello World")
    .add(label, BorderLayout.CENTER)
    .addWindowListener(new MainFrameListener())
    .setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE)
    .pack()
    .setLocationRelativeTo(null)
    .setVisible(true);

It’s amazing how much cleaner the code looks just by eliminating all those mainFrame references.

But wait… doesn’t this look familiar from somewhere? Doesn’t it remind you of a certain language feature you may have used years ago?

Yes, you’re right! It looks remarkably like the “with” control structure available in Delphi/Pascal and VisualBasic! If Java also supported it, the above example could be rewritten like this:


with (new JFrame("Hello World")) {
    add(label, BorderLayout.CENTER);
    addWindowListener(new MainFrameListener());
    setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    pack();
    setLocationRelativeTo(null);
    setVisible(true);
}

It looks almost almost exactly the same as the one using the fluent interface, doesn’t it?

The main difference is that such a built-in construct works with any object you happen to throw at it, doesn’t require any additional effort from the library designer, and doesn’t require you to write repetitive code or wrapper classes if the library author failed to include the fluent interface pattern into the library in the first place. It also doesn’t interfere with the command-query separation principle and is perfectly compatible with step through debuggers.

But the fluent interface pattern does make it possible for us to have a special name for a simple concept, a Wikipedia entry for it, and dozens of blog posts about a solution to a problem that’s been solved, in a better way, decades ago.

Tags: , , ,