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 | ||
{ | { | ||
using System; |
using System; | ||
|
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); | ||
} |
} | ||
|
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); | ||
} |
} | ||
|
public class Configuration : IConfiguration | ||
{ | { | ||
string color; | string color; | ||
int height; | int height; | ||
int length; | int length; | ||
int width; |
int width; | ||
void SetColor(string color) | void SetColor(string color) | ||
{ | { | ||
this.color = color; | this.color = color; | ||
} |
} | ||
void SetHeight(int height) | void SetHeight(int height) | ||
{ | { | ||
this.height = height; | this.height = height; | ||
} |
} | ||
void SetLength(int length) | void SetLength(int length) | ||
{ | { | ||
this.length = length; | this.length = length; | ||
} |
} | ||
void SetDepth(int depth) | void SetDepth(int depth) | ||
{ | { | ||
this.depth = depth; | this.depth = depth; | ||
} | } | ||
} |
} | ||
|
public class ConfigurationFluent : IConfigurationFluent | ||
{ | { | ||
string color; | string color; | ||
int height; | int height; | ||
int length; | int length; | ||
int width; |
int width; | ||
IConfigurationFluent SetColor(string color) | IConfigurationFluent SetColor(string color) | ||
{ | { | ||
this.color = color; | this.color = color; | ||
return this; | return this; | ||
} |
} | ||
IConfigurationFluent SetHeight(int height) | IConfigurationFluent SetHeight(int height) | ||
{ | { | ||
this.height = height; | this.height = height; | ||
return this; | return this; | ||
} |
} | ||
IConfigurationFluent SetLength(int length) | IConfigurationFluent SetLength(int length) | ||
{ | { | ||
this.length = length; | this.length = length; | ||
return this; | return this; | ||
} |
} | ||
IConfigurationFluent SetDepth(int depth) | IConfigurationFluent SetDepth(int depth) | ||
{ | { | ||
Line 74: | Line 78: | ||
return this; | return this; | ||
} | } | ||
} |
} | ||
|
public class ExampleProgram | ||
{ | { | ||
Line 85: | Line 90: | ||
config.SetHeight(1); | config.SetHeight(1); | ||
config.SetLength(2); | config.SetLength(2); | ||
config.SetDepth(3); |
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 | ||
class GlutApp { | class GlutApp { | ||
private: | private: | ||
Line 128: | Line 135: | ||
void create(); | void create(); | ||
}; | }; | ||
|
// 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); |
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 | ||
class FluentGlutApp : private GlutApp { | class FluentGlutApp : private GlutApp { | ||
public: | public: | ||
FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} |
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 | ||
void create() { | void create() { | ||
GlutApp::create(); | GlutApp::create(); | ||
} | } | ||
}; | }; | ||
|
// 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(); }