In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). The term was coined in 2005 by Eric Evans and Martin Fowler.
Implementation
A fluent interface is normally implemented by using method chaining to implement method cascading (in languages that do not natively support cascading), concretely by having each method return the object to which it is attached, often referred to as this or self. Stated more abstractly, a fluent interface relays the instruction context of a subsequent call in method chaining, where generally the context is Defined through the return value of a called method Self-referential, where the new context is equivalent to the last context Terminated through the return of a void context
Note that a "fluent interface" means more than just method cascading via chaining; it entails designing an interface that reads like a DSL, using other techniques like "nested functions and object scoping".
History
The term "fluent interface" was coined in late 2005, though this overall style of interface dates to the invention of method cascading in Smalltalk in the 1970s, and numerous examples in the 1980s. A common example is the iostream library in C++, which uses the << or >> operators for the message passing, sending multiple data to the same object and allowing "manipulators" for other method calls. Other early examples include the Garnet system (from 1988 in Lisp) and the Amulet system (from 1994 in C++) which used this style for object creation and property assignment.
Examples
C#
C# uses fluent programming extensively in LINQ to build queries using "standard query operators". The implementation is based on extension methods.
var translations = new Dictionary<string, string>
{
{ "cat", "chat"}, { "dog", "chien"}, { "fish", "poisson"}, { "bird", "oiseau"} };
// Find translations for English words containing the letter "a", // sorted by length and displayed in uppercase IEnumerable<string> query = translations .Where(t => t.Key.Contains("a")) .OrderBy(t => t.Value.Length) .Select(t => t.Value.ToUpper());
// The same query constructed progressively: var filtered = translations.Where(t => t.Key.Contains("a")); var sorted = filtered.OrderBy (t => t.Value.Length); var finalQuery = sorted.Select (t => t.Value.ToUpper()); Fluent interface can also be used to chain a set of method, which operates/shares the same object. Instead of creating a customer class, we can create a data context which can be decorated with fluent interface as follows. // Defines the data context class Context { public string FirstName { get; set; } public string LastName { get; set; } public string Sex { get; set; } public string Address { get; set; } }
class Customer
{
private Context _context = new Context(); // Initializes the context
// set the value for properties
public Customer FirstName(string firstName) { _context.FirstName = firstName; return this; }
public Customer LastName(string lastName) { _context.LastName = lastName; return this; }
public Customer Sex(string sex) { _context.Sex = sex; return this; }
public Customer Address(string address) { _context.Address = address; return this; }
// Prints the data to console
public void Print() { Console.WriteLine($"First name: { _context.FirstName} \nLast name: { _context.LastName} \nSex: { _context.Sex} \nAddress: { _context.Address}"); } }
class Program
{
static void Main(string[] args) { // Object creation Customer c1 = new Customer(); // Using the method chaining to assign & print data with a single line c1.FirstName("vinod").LastName("srivastav").Sex("male").Address("bangalore").Print(); } }
C++
A common use of the fluent interface in C++ is the standard iostream, which chains overloaded operators.
The following is an example of providing a fluent interface wrapper on top of a more traditional interface in C++: