Overview

The Fluent Interface pattern is a Behavioural design pattern that provides a chainable and expressive API for interacting with objects. It allows methods to return the same object, enabling a sequence of method calls to be made in a single statement. This simplifies the code and makes it more readable, while abstracting the complexity of interacting with the underlying object.

Think about when you’ve built a database query, configured a service, or set up routes in a framework like Laravel. You’ve probably chained methods together to create clear, expressive, and compact code. That’s a Fluent Interface in action!

Example

Let’s explore how the Fluent Interface pattern can make building queries more expressive and readable. We'll use a Query class to construct SQL-like queries.

Here is a class definition:

class Query
{
    private string $query = '';

    public function select(string $columns): self
    {
        $this->query .= sprintf('SELECT %s ', $columns);
        return $this;
    }

    public function from(string $table): self
    {
        $this->query .= sprintf('FROM %s ', $table);
        return $this;
    }

    public function where(string $condition): self
    {
        $this->query .= sprintf('WHERE %s ', $condition);
        return $this;
    }

    public function orderBy(string $column, string $direction = 'ASC'): self
    {
        $this->query .= sprintf('ORDER BY %s %s ', $column, $direction);
        return $this;
    }

    public function getQuery(): string
    {
        return trim($this->query);
    }
}

With this implementation, you can chain method calls to build a query:

$query = new Query();
$sql = $query->select('id, name')
             ->from('users')
             ->where('age > 18')
             ->orderBy('name')
             ->getQuery();

// Output: SELECT id, name FROM users WHERE age > 18 ORDER BY name
echo $sql;

An alternative version without chaining would require invoking each method individually and managing state manually:

$query = new Query();

$query->select('id, name');
$query->from('users');
$query->where('age > 18');
$query->orderBy('name');

$sql = $query->getQuery();

// Output: SELECT id, name FROM users WHERE age > 18 ORDER BY name
echo $sql;

See the difference? Let’s do a quick comparison:

Fluent Interface

  • Pros:

    • Clean and expressive code.

    • Reduces boilerplate and repetitive statements.

    • Encourages a logical flow of operations.

  • Cons:

    • May be harder to debug if one step fails in a long chain.

Non-Chained Version

  • Pros:

    • More explicit and straightforward for debugging.

    • Easier to modify intermediate steps if needed.

  • Cons:

    • Requires more code to achieve the same result.

    • Can lead to a cluttered and less expressive implementation.

That’s it! Design patterns aren’t scary, they’re actually pretty simple (and cool!).

Want to see the Fluent Interface Pattern in action? Check out this a few simple PHP examples: Github

The Grumpy Dev is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.