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 14:48, 27 September 2007 edit72.43.214.108 (talk) Examples← Previous edit Revision as of 14:07, 16 October 2007 edit undoRich257 (talk | contribs)Extended confirmed users19,185 editsm Formatting and linkingNext edit →
Line 1: Line 1:
In ], a fluent interface (as first coined by Eric Evans and ]) is an objected oriented construct that defines a behavior capable of relaying the instruction context of a subsequent call. Generally, the context is In ], a '''fluent interface''' (as first coined by Eric Evans and ]) is an ] that defines a behavior capable of relaying the instruction context of a subsequent call. Generally, the context is
* defined through the return value of a called method * defined through the return value of a called method
* self referential, where the new context is equivalent to the last context * self referential, where the new context is equivalent to the last context
Line 7: Line 7:
==Examples== ==Examples==
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 ]: 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 ]:
<source lang="csharp">


'''namespace Example.FluentInterfaces''' namespace Example.FluentInterfaces
{ {
using System;<br /> using System;
'''public interface IConfiguration''' public interface IConfiguration
{ {
void SetColor(string color); void SetColor(string color);
Line 17: Line 18:
void SetLength(int length); void SetLength(int length);
void SetDepth(int depth); void SetDepth(int depth);
}<br /> }

'''public interface IConfigurationFluent''' public interface IConfigurationFluent
{ {
IConfigurationFluent SetColor(string color); IConfigurationFluent SetColor(string color);
Line 24: Line 26:
IConfigurationFluent SetLength(int length); IConfigurationFluent SetLength(int length);
IConfigurationFluent SetDepth(int depth); IConfigurationFluent SetDepth(int depth);
}<br /> }

'''public class Configuration : IConfiguration''' public class Configuration : IConfiguration
{ {
string color; string color;
int height; int height;
int length; int length;
int width;<br /> int width;
void SetColor(string color) void SetColor(string color)
{ {
this.color = color; this.color = color;
}<br /> }
void SetHeight(int height) void SetHeight(int height)
{ {
this.height = height; this.height = height;
}<br /> }
void SetLength(int length) void SetLength(int length)
{ {
this.length = length; this.length = length;
}<br /> }
void SetDepth(int depth) void SetDepth(int depth)
{ {
this.depth = depth; this.depth = depth;
} }
} <br /> }

'''public class ConfigurationFluent : IConfigurationFluent''' public class ConfigurationFluent : IConfigurationFluent
{ {
string color; string color;
int height; int height;
int length; int length;
int width;<br /> int width;
IConfigurationFluent SetColor(string color) IConfigurationFluent SetColor(string color)
{ {
this.color = color; this.color = color;
return this; return this;
}<br /> }
IConfigurationFluent SetHeight(int height) IConfigurationFluent SetHeight(int height)
{ {
this.height = height; this.height = height;
return this; return this;
}<br /> }
IConfigurationFluent SetLength(int length) IConfigurationFluent SetLength(int length)
{ {
this.length = length; this.length = length;
return this; return this;
}<br /> }
IConfigurationFluent SetDepth(int depth) IConfigurationFluent SetDepth(int depth)
{ {
Line 74: Line 78:
return this; return this;
} }
}<br /><br /> }

'''public class ExampleProgram''' public class ExampleProgram
{ {
Line 85: Line 90:
config.SetHeight(1); config.SetHeight(1);
config.SetLength(2); config.SetLength(2);
config.SetDepth(3);<br /> config.SetDepth(3);
//FluentExample //FluentExample
IConfigurationFluent config = IConfigurationFluent config =
Line 95: Line 100:
} }
} }
</source>


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


<source lang="c">
''// basic definition'' // basic definition
class GlutApp { class GlutApp {
private: private:
Line 128: Line 135:
void create(); void create();
}; };
''// basic usage'' // basic usage
int main(int argc, char **argv) { int main(int argc, char **argv) {
GlutApp app(argc, argv); GlutApp app(argc, argv);
app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); ''// Set framebuffer params'' app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); // Set framebuffer params
app.setWindowSize(500, 500); ''// Set window params'' app.setWindowSize(500, 500); ''// Set window params''
app.setWindowPosition(200, 200); app.setWindowPosition(200, 200);
Line 138: Line 145:
} }


''// Fluent wrapper'' // Fluent wrapper
class FluentGlutApp : private GlutApp { class FluentGlutApp : private GlutApp {
public: public:
FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} ''// inherit parent constructor'' FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} // inherit parent constructor
FluentGlutApp &withDoubleBuffer() { FluentGlutApp &withDoubleBuffer() {
setDisplayMode(getDisplayMode() | GLUT_DOUBLE); setDisplayMode(getDisplayMode() | GLUT_DOUBLE);
Line 170: Line 177:
return *this; return *this;
} }
''// it doesn't make sense to chain after create(), so don't return *this'' // it doesn't make sense to chain after create(), so don't return *this
void create() { void create() {
GlutApp::create(); GlutApp::create();
} }
}; };
''// basic usage'' // basic usage
int main(int argc, char **argv) { int main(int argc, char **argv) {
FluentGlutApp app(argc, argv) FluentGlutApp app(argc, argv)
Line 183: Line 190:
app.create(); app.create();
} }
</source>


==External links== ==External links==

Revision as of 14:07, 16 October 2007

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is an objected oriented construct that defines a behavior capable of relaying the instruction context of a subsequent call. 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, although some engineers find the the style difficult to read. A second criticism is that generally, programming needs are too dynamic to rely on the static contact definition offered by a fluent interface.

Examples

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 width;
        void SetColor(string color)
        {
           this.color = color;
        }
        void SetHeight(int height)
        {
           this.height = height;
        }
        void SetLength(int length)
        {
           this.length = length;
        }
        void SetDepth(int depth)
        {
           this.depth = depth;
        }
    }
    public class ConfigurationFluent : IConfigurationFluent
    {
        string color;
        int height;
        int length;
        int width;
        IConfigurationFluent SetColor(string color)
        {
           this.color = color;
           return this;
        }
        IConfigurationFluent SetHeight(int height)
        {
           this.height = height;
           return this;
        }
        IConfigurationFluent SetLength(int length)
        {
           this.length = length;
           return this;
        }
        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 config = 
                  new ConfigurationFluent().SetColor("blue")
                                           .SetHeight(1)
                                           .SetLength(2)
                                           .SetDepth(3);
        }
    }
 }

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;
     }
     void 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(int w, int 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();
 }

External links