رابط فلوئنت

در مهندسی نرم‌افزار یک رابط فصیح (که توسط اریک ایوانز و مارتین فاولر) راهی است برای پیاده‌سازی رابط برنامه‌نویسی که کدهایی با خوانایی بهتر را پشتیبانی کند.
نمونه‌ها
دلفی
unit FluentInterface;
interface
type
IConfiguration = interface
procedure SetColor(Color: string);
procedure SetHeight(height: integer);
procedure SetLength(length: integer);
procedure SetDepth(depth: integer);
end;
IConfigurationFluent = interface
function SetColor(Color: string): IConfigurationFluent;
function SetHeight(height: integer): IConfigurationFluent;
function SetLength(length: integer): IConfigurationFluent;
function SetDepth(depth: integer): IConfigurationFluent;
end;
TConfiguration = class(TInterfacedObject, IConfiguration)
private
FColor: string;
FHeight: integer;
FLength: integer;
FDepth: integer;
protected
procedure SetColor(Color: string);
procedure SetHeight(height: integer);
procedure SetLength(length: integer);
procedure SetDepth(depth: integer);
end;
TConfigurationFluent = class(TInterfacedObject, IConfigurationFluent)
private
FColor: string;
FHeight: integer;
FLength: integer;
FDepth: integer;
protected
function SetColor(Color: string): IConfigurationFluent;
function SetHeight(height: integer): IConfigurationFluent;
function SetLength(length: integer): IConfigurationFluent;
function SetDepth(depth: integer): IConfigurationFluent;
public
class function New: IConfigurationFluent;
end;
implementation
procedure TConfiguration.SetColor(Color: string);
begin
FColor := Color;
end;
procedure TConfiguration.SetDepth(depth: integer);
begin
FDepth := depth;
end;
procedure TConfiguration.SetHeight(height: integer);
begin
FHeight := height;
end;
procedure TConfiguration.SetLength(length: integer);
begin
FLength := length;
end;
class function TConfigurationFluent.New: IConfigurationFluent;
begin
Result := Create;
end;
function TConfigurationFluent.SetColor(Color: string): IConfigurationFluent;
begin
FColor := Color;
Result := Self;
end;
function TConfigurationFluent.SetDepth(depth: integer): IConfigurationFluent;
begin
FDepth := depth;
Result := Self;
end;
function TConfigurationFluent.SetHeight(height: integer): IConfigurationFluent;
begin
FHeight := height;
Result := Self;
end;
function TConfigurationFluent.SetLength(length: integer): IConfigurationFluent;
begin
FLength := length;
Result := Self;
end;
end.
Basic Usage:
var C, D: IConfiguration;
E: IConfigurationFluent;
begin
C := TConfiguration.Create;
C.SetColor(blue);
C.SetHeight(1);
C.SetLength(2);
C.SetDepth(3);
{ same "non-fluent interface" accessed using the "with" statement
D := TConfiguration.Create;
with D do begin
SetColor(blue);
SetHeight(1);
SetLength(2);
SetDepth(3)
end;
E := TConfigurationFluent.New
.SetColor(Blue)
.SetHeight(1)
.SetLength(2)
.SetDepth(3);
end;
C
namespace Example.FluentInterfaces
#region Standard Example
public interface IConfiguration
string Color { set;
int Height { set;
int Length { set;
int Depth { set;
public class Configuration : IConfiguration
string color;
int height;
int length;
int depth;
public string Color
set { color = value;
public int Height
set { height = value;
public int Length
set { length = value;
public int Depth
set { depth = value;
#endregion
#region Fluent Example
public interface IConfigurationFluent
IConfigurationFluent SetColor(string color);
IConfigurationFluent SetHeight(int height);
IConfigurationFluent SetLength(int length);
IConfigurationFluent SetDepth(int 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;
#endregion
public class ExampleProgram
public static void Main(string args)
//Standard Example
IConfiguration config = new Configuration
Color = "blue",
Height = 1,
Length = 2,
Depth = 3
//Fluent Example
IConfigurationFluent fluentConfig =
new ConfigurationFluent().SetColor("blue")
.SetHeight(1)
.SetLength(2)
.SetDepth(3);
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 doesnt make sense to chain after create(), so dont return *this
void create() {
GlutApp::create();
// basic usage
int main(int argc, char **argv) {
FluentGlutApp(argc, argv)
.withDoubleBuffer().withRGBA().withAlpha().withDepth()
.at(200, 200).across(500, 500)
.named("My OpenGL/GLUT App")
.create();
Java
public Collection 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();
String datesStr = new String {"12-10-1492", "06-12-1978" ;
List dates =
Op.on(datesStr).toList().map(FnString.toCalendar("dd-MM-yyyy")).get();
Collection mockCollection = EasyMock.createMock(Collection.class);
EasyMock.expect(mockCollection.remove(null)).andThrow(new NullPointerException()).atLeastOnce();
نمونه‌های دیگر جاوا
In Java, the LayoutManager interface defines how Container objects can have controlled Component placement. One of the more powerful LayoutManager implementations is the GridBagLayout class which requires the use of the GridBagConstraints class to specify how layout control occurs. A typical example of the use of this class is something like the following.
GridBagLayout gl = new GridBagLayout();
JPanel p = new JPanel();
p.setLayout( gl );
JLabel l = new JLabel("Name:");
JTextField nm = new JTextField(10);
GridBagConstraints gc = new GridBagConstraints();
gc.gridx = 0;
gc.gridy = 0;
gc.fill = GridBagConstraints.NONE;
p.add( l, gc );
gc.gridx = 1;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1;
p.add( nm, gc );
This creates a lot of code and makes it difficult to see what exactly is happening here. The Packer class, visible at http://packer.dev.java.net, provides a Fluent mechanism for using this class so that you would instead write:
JPanel p = new JPanel();
Packer pk = new Packer( p );
JLabel l = new JLabel("Name:");
JTextField nm = new JTextField(10);
pk.pack( l ).gridx(0).gridy(0);
pk.pack( nm ).gridx(1).gridy(0).fillx();
There are many places where Fluent APIs can greatly simplify how software is written and help create an API language that helps users be much more productive and comfortable with the API because the return value of a method always provides a context for further actions in that context.
PHP
The following is an example of a class with a fluent interface implemented in 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 without fluent interface
$myCar2 = new Car();
$myCar2->setSpeed(100);
$myCar2->setColor(blue);
$myCar2->setDoors(5);
JavaScript
The following is an example of a class with a fluent interface implemented in جاوااسکریپت:
var Car = function(){
var speed, color, doors, pub;
function setSpeed(new_speed) {
speed = new_speed;
return pub;
function setColor(new_color) {
color = new_color;
return pub;
function setDoors(new_doors) {
doors = new_doors;
return pub;
pub = {
setSpeed: setSpeed,
setColor: setColor,
setDoors: setDoors,
return pub;
// Fluent interface
myCar = Car();
myCar.setSpeed(100).setColor(blue).setDoors(5);
// Example without fluent interface
myCar2 = Car();
myCar2.setSpeed(100);
myCar2.setColor(blue);
myCar2.setDoors(5);