Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand how to create fluent interfaces, and when to use them

How would one create a fluent interface instead of a more tradition approach? Here is a traditional approach:

Interface:

interface IXmlDocumentFactory<T>
{
    XmlDocument CreateXml()                    //serializes just the data
    XmlDocument CreateXml(XmlSchema schema)    //serializes data and includes schema
}

interface IXmlSchemaFactory<T>
{
    XmlSchema CreateXmlSchema()                //generates schema dynamically from type
}

Usage:

var xmlDocFactory = new XmlDocumentFactory<Foo>(foo);
var xmlDocument = xmlDocFactory.CreateXml();

//or...

var xmlDocFactory = new XmlDocumentFactory<Foo>(foo);
var xmlSchemaFactory = new XmlSchemaFactory<Foo>();
var xmlDocument = xmlDocFactory.CreateXml(xmlSchemaFactory.CreateXmlSchema());

I'd like to be able to say:

var xmlDocument = new XmlDocumentFactory<Foo>(foo).CreateXml().IncludeSchema();
//or...
var xmlDocument = new XmlDocumentFacotry<Foo>(foo).CreateXml(); 

Lastly, is this situation a good fit for fluent interfaces? Or would a more traditional approach make more sense?

like image 591
Matt Avatar asked May 26 '11 13:05

Matt


People also ask

What is the fluent user interface and how does it work?

Fluent Ribbon User Interface The Fluent interface makes it easier to find powerful features by replacing menus and toolbars with a Ribbon that organizes and presents capabilities in a way that corresponds more directly to how people work.

What is fluent interface in C#?

A fluent interface is an object-oriented API that depends largely on method chaining. The goal of a fluent interface is to reduce code complexity, make the code readable, and create a domain specific language (DSL). It is a type of method chaining in which the context is maintained using a chain.

Is fluent interface good?

Fluent interface, first coined as a term by Martin Fowler, is a very convenient way of communicating with objects in OOP. It makes their facades easier to use and understand. However, it ruins their internal design, making them more difficult to maintain.

What is fluent interface in Java?

A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.


2 Answers

The key to making an interface fluent is to ensure the methods all return instances of the interface itself, or some other object that also implements the interface that can continue the processing.

So in your case each of your IXmlDocumentFactory methods has to return an IXmlDocumentFactory so you can continue to call. The final method, if there is one, returns the type you really want?

It makes for very readable code but one thing that still gives me a bit of the willies is return-checking. You have to make very sure that null's can't be returned or else the next 'fluent call' will fail.

like image 52
n8wrl Avatar answered Oct 14 '22 08:10

n8wrl


Three things are important in my mind:

1.) There is an initial method that returns the fluent interface you are going to work with

2.) Each method in the class that implements your fluent interface returns itself so you can continue chaining - these are the real fluent methods.

3.) There is a final method that returns the type that you really want to build.

In your example since you only have two methods, its borderline useful - usually you would have more methods in a fluent interface. Alternatively (which I personally prefer) you can offer both options in your API: A fluent API and a more traditional API (i.e. with optional parameters).

In your case would do something like this:

Edited to respond to comment.

public interface IXmlDocumentFactory<T>
{
    XmlDocument Create();                    //serializes just the data
    IXmlDocumentFactory<T> WithSchema(XmlSchema schema);    //serializes data and includes schema
}

public class DocumentFactory<T> : IXmlDocumentFactory<T>
{
    private XmlSchema _schema;
    private T _data;

    public DocumentFactory(T data)
    {
        _data = data;
    }
    public IXmlDocumentFactory<T> WithSchema(XmlSchema schema)
    {
        _schema = schema;
        return this;
    }
    public XmlDocument Create()
    {
        if (_schema != null)
        {
            //..use schema/data
            return new XmlDocument();
        }
        else //use data
            return new XmlDocument();
    }

    public static IXmlDocumentFactory<T> From(T data)
    {
        return new DocumentFactory<T>(data);
    }
}

Then you can use it like this:

var xmlDoc = DocumentFactory<int>.From(42)
                                 .WithSchema(new XmlSchema())
                                 .Create();

var xmlDoc = DocumentFactory<int>.From(42)
                                 .Create();
like image 34
BrokenGlass Avatar answered Oct 14 '22 07:10

BrokenGlass