Fluent interface

from Wikipedia, the free encyclopedia

Fluent interfaces (German often translated as: "liquid interfaces", more aptly: "speaking interfaces") are a concept for programming interfaces in software development, which, if followed, you can program almost in the form of sentences of natural language. The program code written afterwards is easy to read and makes it easier to understand the program.

Interfaces are often used incorrectly. Fluent interfaces can encourage their correct use by choosing a grammar for them that is noticeably violated by incorrect use. There are two ways of implementing such "speaking interfaces", using method chaining (method chains) or using nested functions (embedded functions).

Basics

Eric Evans and Martin Fowler are considered to be the founders of the Fluent Interfaces concept . In the example implementation of the Specification design pattern , they invented the concept of creating new objects in a meaningful way using chains of methods.

 Specification colorSpec = new ColorSpecification();
 Specification lengthSpec = new LengthSpecification();
 if(colorSpec.and(lengthSpec).isSatisfiedBy(obj)) {
     ...
 }

In the example above, the condition of the if statement expressly states that the object obj is tested for both conditions. Another example is the speaking creation of a date.

 DateFactory.newDate().year(2009).month(2).day(7);

In contrast to the use of a constructor , in which the meaning of the three numerical values ​​would be given hidden by their position in the call, the above method names expressly show what meaning the individual values ​​should have. The developer of such an interface can also restrict the order in which the methods can be called. This means that method calls that expect multiple parameters can be written much more easily.

Fluent interfaces play a particularly important role in Evans' domain-driven design , as they enable him to express specific properties from a domain explicitly in the program code. Fluent interfaces belong to the so-called internal domain-specific languages , also known as embedded language. They are domain-specific languages that are implemented in the syntax of a programming language .

implementation

Naive without grammar

The sample implementation by Evans and Fowler for the Specifications design pattern was kept very simple. To enable a method chain with and as above, only the new method and () has been added to the "Specification" interface .

 public interface Specification {

     Specification and(Specification spec);

     boolean isSatisfiedBy(Object obj);

 }

When and () is called, each specification delivers another, which in turn can come from a call to the and () method . This naive approach, however, enriches the implementation of types with functionalities that are far removed from their actual purpose. The main disadvantage, however, is that methods can be chained in any order.

With grammar

The order in which the methods of a method chain can be strung together often plays a major role. The following example shows the use of a fluent interface that adds a few days and hours to an object of the type Date .

Date date = CalendarUtils
        .add(5).days()
        .add(10).hours()
        .to(date);

If, as in the naive approach, one would always return the same type with each call of a method, then the "sentence" can be terminated prematurely or incorrectly by not concatenating all mandatory "parts of the sentence" or some multiple times. So that such an exclusive grammar is enforced, each call of a method must return a different type, which only contains the following methods that are still permitted. In the following example you can see how the call of the method newDate () of DateUtils leads to the return of a mediator . This then has the follow-up method add ready. Calling the add method also leads to the return of a new mediator , etc.

 public class DateUtils {
    public static Mediator newDate() {
        ...
    }
 }

 public class Mediator {
     public Mediator2 add(int i) {
         ...
     }
 }

 public class Mediator2 {
     public Mediator3 days() {
         ...
     }
 }

...
// possible sentence
DateUtils.newDate().add(5).days(). ...

Bernd Schiffer calls this mediators as descriptors . With the above example, a grammar is implemented that precisely specifies the sequence in which the methods can be called. In addition, the method chain does not return a desired object of the Date type as long as it is not yet complete. Therefore, when using a DateUtils class implemented in this way, errors appear when the application program is compiled and not at runtime.

advantages

The advantages lie in the easier development of programs that use them and the better readability of the program code written for them.

  • Fluent interfaces can come very close to a natural-language sentence. So you only have to comment a little.
  • A sentence-like fluent interface and the permissible sentence structure implied by it give the user a clearer idea of ​​the functionalities offered and their possible use.
  • A development environment with autocomplete, such as Eclipse, shows which next methods can be called.

disadvantage

The disadvantages are the effort for the fluent interface itself and the difficult development of programs that use it.

  • The implementation of a grammar for fluent interface is very complex and the necessary network of mediators quickly becomes confusing. In addition, it is difficult to understand at their level which sentence constructions are possible. By modeling fluent interfaces in the form of diagrams, an attempt is made to avoid this disadvantage. The necessary mediator code is generated automatically from a model so that it is only necessary to implement the behavior of the fluent interface yourself.
  • A long chain of method calls on the same line makes debugging difficult, since a call stack typically only contains the line of the error, but not the column in the source file. The same applies to the assignment of warnings from the static code analysis. In addition, breakpoints can often only be set on complete statements, not on individual method calls within them.

Possible uses

Fluent interfaces are used for a variety of purposes. The focus is always on making explicit what is anchored in a domain.

  • Packaging of functionalities
    As shown above, Fluent Interfaces can offer existing functionalities in a more understandable way.
  • Liquid builder
    Transfer of the Fluent Interface concept to the Bauauer design template .
  • Mapping of foreign syntax
    With the help of Fluent Interfaces, character strings that appear in the program code can be used for interpreted languages ​​such as B. Replace SQL , XPath or HQL conceptually more easily with calls.

Note

Some programming languages ​​support named parameters, e.g. B. Smalltalk or ABAP . With these, the concept of the fluent interface does not make sense, since the method interfaces must already be speaking due to the properties of the language used.

Example small talk:

  object param1:foo param2:bar

Example ABAP:

  lo_object->myMethod(
               iv_param1 = foo
               iv_param2 = bar
  ).

Web links

Individual evidence

  1. ^ Martin Fowler: Fluent Interfaces . Bliki entry
  2. Specifications (PDF; 79 kB)
  3. ^ Martin Fowler: Domain Specific Language . Bliki entry
  4. ^ Evolving an Embedded Domain-Specific Language in Java . (PDF)
  5. a b Liquid Builder