fluent interface
LINEЭто статья о fluent interface, что это такое, как и зачем это использовать.
Method chaining
Давайте посмотрим на пример небольшого фрагмента кода. Здесь мы создаем строку "hello world", заменяем "world" на "everyone", заменяем все буквы на заглавные, разделяем строку на список строк по пробельному символу и выводим только первый элемент. В итоге у нас получится строка "HELLO". Для каждой новой операции модификации строки мы использовали новую переменную, в которую записывали результат некоторой операции над старой строкой. Всего у нас вышло 4 строки, что равно количеству операций.

Есть такое понятие как сигнатура метода. Это то, как мы можем отличить один метод от другого: название метода и входные параметры. Выходное значение не учитывается в сигнатуре, но в нашем примере, предположим, что оно также учитывается (частным случаем выходного значения может быть void, т.е. метод ничего не возвращает). Если мы посмотрим на сигнатуру каждого метода, который мы использовали для трансформации, то можно заметить, что все они(replace, toUpperCase, split(" ")[0]) возвращают String, и все это - методы класса String. Т.е. это методы некоторого экземпляра класса, которые также возвращают экземпляра того же класса, в данном случае String.
Если попробовать визуально изобразить то, как мы трансформировали нашу исходную строку, мы получим что то вроде этого

Каждый метод возвращает объект класса String. Что если мы обойдемся от ненужных переменных?

Да, этот фрагмент делает все тоже самое, но без дополнительных переменных. Но что более важно - его легче прочесть и понять. Каждая строка - короткая инструкция по трансформации.
Когда мы связываем несколько методов подобным образом, мы как бы сцепляем методы в некоторую структуру. У нас образуется "цепь" вызовов, один после другого. Это и есть цепочка вызовов или method chaining.
Fluent interface
Понимая method chaining, можно перейти к fluent interface.
Это такой способ создания API (класса, модуля, слоя), в котором используется method chaining для больший выразительности. Для примера придумаем небольшое API обработки изображения. Напишем класс Image, в конструктор которому поступает файл изображения и формат изображения. После чего мы читаем изображение из файла и записываем его в BufferedImage

Теперь добавим наш fluent api. Это будут несколько методов, которые возвращают this и преобразуют изображение: конвертируют формат, применяют фильтр, поворачивают изображение (реализация методов не приводится, т.к. это в данном случае совсем неважно). Последний метод save сохраняет полученный результат в файл.

Вот зачем все это было нужно

Теперь мы можем создавать новые изображения подобным образом. Визуально такой стиль очень хорошо понятен читающему: создать изображение, конвертировать, повернуть на 45 градусов, применить подряд 2 фильтра и сохранить в файл. Способ, который использовался для создания класса и методов, называется fluent interface.
DSL
Fluent interface можно использовать в для написания DSL (Domain-Specific Language), точнее для того, что называется Internal DSL. Тема DSL довольно большая, но в двух словах - это возможность описать свой язык, учитывающий конкретные особенности конкретной области, возможно поверх уже существующего языка. Мы как бы ограничиваем язык, который может использоваться для любых целей, только конкретной областью и задаем нужные нам правила/ограничения (статья Мартина Фаулера о DSL).
С помощью fluent interface на java можно создать свой DSL, но все же java не лучший для этого язык.
Для примера попробуем создать DSL для создания расписаний.
Создадим класс Action, который будет описывать некоторую активность: время начала, время окончания, название и приоритет

Теперь добавим класс нашего расписания Schedule. Расписание включает в себя список действий (Action) и builder для каждого действия. Метод add возвращает новый builder для конфигурации конкретного действия.

Вот как выглядит ActionBuilder (вложенный в Schedule)

Здесь каждый метод просто назначает свойство и возвращает себя. Метод submit создает новый объект Action, добавляет его в расписание и возвращает расписание. Теперь все это можно использовать так

Для использования этого класса почти не нужно знать самого языка java, достаточно запомнить несколько методов и можно составлять расписания.
Builder
Если вы сталкивались с таким паттерном как строитель (или builder), то вам знаком fluent interface. Самый простой пример - Stringbuilder. Он позволяет не создавать новый объект String при каждом изменении строки, эффективно расходуя память.

Создаем новый StringBuilder, добавляем "dlrow" (world наоборот), переворачиваем строку, вставляем "hello " и заменяем "hello" на "everyone".
Вот как выглядит типичный builder. Вы создаете класс, добавляете ему несколько параметров, передаете все параметры в конструкторе, но конструктор делаете приватным. Теперь этот конструктор нельзя вызвать извне класса.
Теперь добавляете статический класс с названием класса + Builder, в котором перечисляете все те же параметры и методы установки значений этих параметров. Каждый такой метод возвращает этот же объект builder, и в конце добавляете метод create/build, который возвращает объект изначального класса.
Для примера класс и builder класса Hero с полями силы, ловкости и выносливости

builder будет выглядеть так

Для создания нового героя, мы создаем builder, устанавливаем поля и вызываем метод create

Buuilder - это порождающий паттерн, который в основном нужен тогда, когда у нас много различных способов сконфигурировать объект, слишком много чтобы передать их через конструктор. Обычно у buider есть метод, который возвращает конкретный объект через вызов метода build, create или похожий. Именно с этим паттерном fluent interface используется особенно часто.
Immutable Fluent interface
В примерах выше вызов каждого метода менял состояние объекта. Менялись значения отдельных полей. Но fluent interface можно использовать также и с неизменяемыми классами. Для этого каждый метод должен не менять отдельное поле, а создавать новый объект с уже измененным полем и возвращать этот новый объект. Посмотрим на класс ImmutableUser

Поля name и age объявлены как final, а вызов методов name и age создает и возвращает новый объект ImmutableUser. Можем проверить это, вызвав у объектов метод hashCode:

Примеры
Посмотрим на конкретные примеры fluent interface в том или ином виде
- JOOQ Object Oriented Querying - инструмент для работы с SQL в Java в. Сверху представлен обычный sql запрос, а ниже - в формате JOOQ.

- стандартный iostream в c++. Да, это не совсем про то, но перегрузка операторов позволяет добавлять в поток вывода любое количество строк

- библиотека для тестирования EasyMock

- javascript библиотека jQuery

- добавление анимации view в android

- java stream api

Есть еще множество других примеров использования fluent interface.
Заключение
Fluent interface - способ написания api, при котором используется method chaining для лучшего визуального оформления кода. Такой код довольно легко читать и понимать.
Но это точно не универсальный способ. Не стоит пытаться писать свои классы в подобном стиле без нужных на то причин. Особенно, если методы не связаны между собой.
У fluent interface конечно есть и недостатки. Например, цепочка вызовов может разрастись на десятки строк и читать такой код станет уже сложнее, чем обычный, разделенный на отдельные методы. Не всегда очевидно как обрабатывать ошибки - что произойдет, если один из методов выбросит исключение? Кто и где должен обработать это исключение. Также fluent interface предполагает большое количество методов, а чем больше методов тем выше шанс нарушения принципа единой ответственности. Fluent interface может вести к нарушению инкапсуляции.
Fluent interface это хороший способ написания api, если такой подход уместен. Про него стоит помнить, но не стоит использовать лишь для того, чтобы он был.
Примеры из статьи можно посмотреть здесь.