Misplaced Pages

Fluent interface: Difference between revisions

Article snapshot taken from Wikipedia with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
Browse history interactively← Previous editNext edit →Content deleted Content addedVisualWikitext
Revision as of 10:14, 26 July 2009 edit91.196.215.2 (talk) C++← Previous edit Revision as of 12:00, 18 August 2009 edit undoCrashthe2nd (talk | contribs)1 edit C#: Modified C# source code so that it compilesNext edit →
Line 13: Line 13:
<source lang="csharp"> <source lang="csharp">


namespace Example.FluentInterfaces namespace Example.FluentInterfaces
{ {
using System; using System;

public interface IConfiguration public interface IConfiguration
{ {
Line 38: Line 39:
int length; int length;
int depth; int depth;

void SetColor(string color) public void SetColor(string color)
{ {
this.color = color; this.color = color;
} }

void SetHeight(int height) public void SetHeight(int height)
{ {
this.height = height; this.height = height;
} }

void SetLength(int length) public void SetLength(int length)
{ {
this.length = length; this.length = length;
} }

void SetDepth(int depth) public void SetDepth(int depth)
{ {
this.depth = depth; this.depth = depth;
} }
} }
Line 62: Line 67:
int length; int length;
int depth; int depth;

IConfigurationFluent SetColor(string color) public IConfigurationFluent SetColor(string color)
{ {
this.color = color; this.color = color;
return this; return this;
} }

IConfigurationFluent SetHeight(int height) public IConfigurationFluent SetHeight(int height)
{ {
this.height = height; this.height = height;
return this; return this;
} }

IConfigurationFluent SetLength(int length) public IConfigurationFluent SetLength(int length)
{ {
this.length = length; this.length = length;
return this; return this;
} }

IConfigurationFluent SetDepth(int depth) public IConfigurationFluent SetDepth(int depth)
{ {
this.depth = depth; this.depth = depth;
return this; return this;
} }
} }
Line 86: Line 95:
public class ExampleProgram public class ExampleProgram
{ {
public static void Main(string args) public static void Main(string args)
{ {
Line 95: Line 103:
config.SetLength(2); config.SetLength(2);
config.SetDepth(3); config.SetDepth(3);

//FluentExample //FluentExample
IConfigurationFluent config = IConfigurationFluent fluentConfig =
new ConfigurationFluent().SetColor("blue") new ConfigurationFluent().SetColor("blue")
.SetHeight(1) .SetHeight(1)
Line 103: Line 112:
} }
} }
} }
</source> </source>



Revision as of 12:00, 18 August 2009

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

A fluent interface is normally implemented by using method chaining to relay the instruction context of a subsequent call (but a fluent interface entails more than just method chaining ). 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.

This style is beneficial due to its ability to provide a more fluid feel to the code.

Examples

C#

The following example shows a class implementing a non-fluent interface, another class implementing a fluent counterpart of the aforementioned non-fluent interface, and differences in usage. The example is written in C#:

namespace Example.FluentInterfaces
{
    using System;
    public interface IConfiguration
    {
        void SetColor(string color);
        void SetHeight(int height);
        void SetLength(int length);
        void SetDepth(int depth);
    }
    public interface IConfigurationFluent
    {
        IConfigurationFluent SetColor(string color);
        IConfigurationFluent SetHeight(int height);
        IConfigurationFluent SetLength(int length);
        IConfigurationFluent SetDepth(int depth);
    }
    public class Configuration : IConfiguration
    {
        string color;
        int height;
        int length;
        int depth;
        public void SetColor(string color)
        {
            this.color = color;
        }
        public void SetHeight(int height)
        {
            this.height = height;
        }
        public void SetLength(int length)
        {
            this.length = length;
        }
        public void SetDepth(int depth)
        {
            this.depth = depth;
        }
    }
    public class ConfigurationFluent : IConfigurationFluent
    {
        string color;
        int height;
        int length;
        int depth;
        public IConfigurationFluent SetColor(string color)
        {
            this.color = color;
            return this;
        }
        public IConfigurationFluent SetHeight(int height)
        {
            this.height = height;
            return this;
        }
        public IConfigurationFluent SetLength(int length)
        {
            this.length = length;
            return this;
        }
        public IConfigurationFluent SetDepth(int depth)
        {
            this.depth = depth;
            return this;
        }
    }
    public class ExampleProgram
    {
        public static void Main(string args)
        {
            //Standard Example
            IConfiguration config = new Configuration();
            config.SetColor("blue");
            config.SetHeight(1);
            config.SetLength(2);
            config.SetDepth(3);
            //FluentExample
            IConfigurationFluent fluentConfig =
                  new ConfigurationFluent().SetColor("blue")
                                           .SetHeight(1)
                                           .SetLength(2)
                                           .SetDepth(3);
        }
    }
}

C++

The following is an example of providing a fluent interface wrapper on top of a more traditional interface in C++:

 // basic definition
 class GlutApp {
 private:
     int w_, h_, x_, y_, argc_, display_mode_;
     char **argv_;
     char *title_;
 public:
     GlutApp(int argc, char** argv) {
         argc_ = argc;
         argv_ = argv;
     }
     void setDisplayMode(int mode) {
         display_mode_ = mode;
     }
     int getDisplayMode() {
         return display_mode_;
     }
     void setWindowSize(int w, int h) {
         w_ = w;
         h_ = h;
     }
     void setWindowPosition(int x, int y) {
         x_ = x;
         y_ = y;
     }
     void setTitle(const char *title) {
         title_ = title;
     }
     void create();
 };
 // basic usage
 int main(int argc, char **argv) {
     GlutApp app(argc, argv);
     app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); // Set framebuffer params
     app.setWindowSize(500, 500); // Set window params
     app.setWindowPosition(200, 200);
     app.setTitle("My OpenGL/GLUT App");
     app.create();
 }
 // Fluent wrapper
 class FluentGlutApp : private GlutApp {
 public:
     FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} // inherit parent constructor
     FluentGlutApp &withDoubleBuffer() {
         setDisplayMode(getDisplayMode() | GLUT_DOUBLE);
         return *this;
     }
     FluentGlutApp &withRGBA() {
         setDisplayMode(getDisplayMode() | GLUT_RGBA);
         return *this;
     }
     FluentGlutApp &withAlpha() {
         setDisplayMode(getDisplayMode() | GLUT_ALPHA);
         return *this;
     }
     FluentGlutApp &withDepth() {
         setDisplayMode(getDisplayMode() | GLUT_DEPTH);
         return *this;
     }
     FluentGlutApp &across(int w, int h) {
         setWindowSize(w, h);
         return *this;
     }
     FluentGlutApp &at(int x, int y) {
         setWindowPosition(x, y);
         return *this;
     }
     FluentGlutApp &named(const char *title) {
         setTitle(title);
         return *this;
     }
     // it doesn't make sense to chain after create(), so don't return *this
     void create() {
         GlutApp::create();
     }
 };
 // basic usage
 int main(int argc, char **argv) {
     FluentGlutApp app(argc, argv)
         .withDouble().withRGBA().withAlpha().withDepth()
         .at(200, 200).across(500, 500)
         .named("My OpenGL/GLUT App");
     app.create();
 }

Java

Some APIs in Java follow this practice, like Java Persistence API:

public Collection<Student> findByNameAgeGender(String name, int age, Gender gender) {
    return em.createNamedQuery("Student.findByNameAgeGender")
             .setParameter("name", name)
             .setParameter("age", age)
             .setParameter("gender", gender)
             .setFirstResult(1)
             .setMaxResults(30)
             .setHint("hintName", "hintValue")
             .getResultList();
}

PHP

The following is an example of providing fluent interface in PHP:

<?php
	session_start();
	error_reporting(E_ALL | E_USER_NOTICE);
	require_once 'classes/Loader.php';
	require_once 'config.php';
?>
<?php
	class car {
		private $speed;
		private $color;
		private $doors;
		public function setSpeed($speed){
			$this->speed = $speed;
			return $this;
		}
		public function setColor($color) {
			$this->color = $color;
			return $this;
		}
		public function setDoors($doors) {
			$this->doors = $doors;
			return $this;
		}
	}
	// Fluent interface
	$myCar = new car();
	$myCar->setSpeed(100)->setColor('blue')->setDoors(5);
	// Example withouth fluent interface
	$myCar2 = new car();
	$myCar2->setSpeed(100);
	$myCar2->setColor('blue');
	$myCar2->setDoors(5);
?>

See also

External links

Software design patterns
Gang of Four
patterns
Creational
Structural
Behavioral
Concurrency
patterns
Architectural
patterns
Other
patterns
Books
People
Communities
See also
Category: