流式接口

流式接口（fluent interface）是软件工程中面向对象API的一种实现方式，以提供更为可读的源代码。最早由与Martin Fowler于2005年提出。
通常采取 (具体说是方法链式调用)来转发一系列对象方法调用的上下文 。这个上下文（context）通常是指：
C++的iostream流式调用就是一个典型的例子。Smalltalk在1970年代就实现了。
例子.
JavaScript.
用于数据库查询的jQuery，例如https://github.com/Medium/dynamite :
// getting an item from a table
client.getItem('user-table')
 .setHashKey('userId', 'userA')
 .setRangeKey('column', '@')
 .execute()
 .then(function(data) {
 // data.result: the resulting object
JavaScript使用原型继承与`this`.
// example from http://schier.co/post/method-chaining-in-javascript
// define the class
var Kitten = function() {
 this.name = 'Garfield';
 this.color = 'brown';
 this.gender = 'male';
Kitten.prototype.setName = function(name) {
 this.name = name;
 return this;
Kitten.prototype.setColor = function(color) {
 this.color = color;
 return this;
Kitten.prototype.setGender = function(gender) {
 this.gender = gender;
 return this;
Kitten.prototype.save = function() {
 console.log(
 'saving ' + this.name + ', the ' +
 this.color + ' ' + this.gender + ' kitten...'
 // save to database here...
 return this;
// use it
new Kitten()
 .setName('Bob')
 .setColor('black')
 .setGender('male')
 .save();
Java.
jOOQ库模拟了SQL
Author author = AUTHOR.as("author");
create.selectFrom(author)
 .where(exists(selectOne()
 .from(BOOK)
 .where(BOOK.STATUS.eq(BOOK_STATUS.SOLD_OUT))
 .and(BOOK.AUTHOR_ID.eq(author.ID))));
C#.
C#在LINQ中大量使用 "standard query operators"与扩展方法。
var translations = new Dictionary&lt;string, string&gt;
 {"cat", "chat"},
 {"dog", "chien"},
 {"fish", "poisson"},
// Find translations for English words containing the letter "a",
// sorted by length and displayed in uppercase
IEnumerable&lt;string&gt; query = translations
 .Where (t =&gt; t.Key.Contains("a"))
 .OrderBy (t =&gt; t.Value.Length)
 .Select (t =&gt; t.Value.ToUpper());
// The same query constructed progressively:
var filtered = translations.Where (t =&gt; t.Key.Contains("a"));
var sorted = filtered.OrderBy (t =&gt; t.Value.Length);
var finalQuery = sorted.Select (t =&gt; t.Value.ToUpper());
流式接口可用于一系列方法，他们运行在同一对象上。
// Defines the data context
class Context
class Customer
 private Context _context = new Context(); // Initializes the context
 // set the value for properties
 public Customer FirstName(string firstName)
 _context.FirstName = firstName;
 return this;
 public Customer LastName(string lastName)
 _context.LastName = lastName;
 return this;
 public Customer Sex(string sex)
 _context.Sex = sex;
 return this;
 public Customer Address(string address)
 _context.Address = address;
 return this;
 // Prints the data to console
 public void Print()
 Console.WriteLine("First name: {0} \nLast name: {1} \nSex: {2} \nAddress: {3}", _context.FirstName, _context.LastName, _context.Sex, _context.Address);
class Program
 static void Main(string[] args)
 // Object creation
 Customer c1 = new Customer();
 // Using the method chaining to assign &amp; print data with a single line
 c1.FirstName("vinod").LastName("srivastav").Sex("male").Address("bangalore").Print();
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;
 // 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 &amp;withDoubleBuffer() {
 setDisplayMode(getDisplayMode() | GLUT_DOUBLE);
 return *this;
 FluentGlutApp &amp;withRGBA() {
 setDisplayMode(getDisplayMode() | GLUT_RGBA);
 return *this;
 FluentGlutApp &amp;withAlpha() {
 setDisplayMode(getDisplayMode() | GLUT_ALPHA);
 return *this;
 FluentGlutApp &amp;withDepth() {
 setDisplayMode(getDisplayMode() | GLUT_DEPTH);
 return *this;
 FluentGlutApp &amp;across(int w, int h) {
 setWindowSize(w, h);
 return *this;
 FluentGlutApp &amp;at(int x, int y) {
 setWindowPosition(x, y);
 return *this;
 FluentGlutApp &amp;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();
 };
 // Fluent 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();
Ruby.
Ruby语言允许修改核心类，这使得流式接口成为原生易于实现。 
class String
 def prefix(raw)
 "#{raw} #{self}"
 end
 def suffix(raw)
 "#{self} #{raw}"
 end
 def indent(raw)
 raw = " " * raw if raw.kind_of? Fixnum
 prefix(raw)
 end
end
message = "there"
puts message.prefix("hello")
 .suffix("world")
 .indent(8)
Scala.
Scala supports a fluent syntax for both method calls and class mixins, using traits and the with keyword. For example:
trait GUIWindow {
 // Rendering methods that return this for fluent drawing
 def set_pen_color(color: Color): this.type
 def move_to(pos: Position): this.type
 def line_to(pos: Position, end_pos: Position): this.type
 def render(): this.type = this // Don't draw anything, just return this, for child implementations to use fluently
 def top_left(): Position
 def bottom_left(): Position
 def top_right(): Position
 def bottom_right(): Position
trait WindowBorder extends GUIWindow {
 def render(): GUIWindow = {
 super.render()
 .move_to(top_left())
 .set_pen_color(Black)
 .line_to(top_right())
 .line_to(bottom_right())
 .line_to(bottom_left())
 .line_to(top_left())
val appWin = new SwingWindow() with WindowBorder
appWin.render()
Perl 6.
In Perl 6, there are many approaches, but one of the simplest is to declare attributes as read/write and use the codice_1 keyword. The type annotations are optional, but the native gradual typing makes it much safer to write directly to public attributes.
class Employee {
 subset Salary of Real where * &gt; 0;
 subset NonEmptyString of Str where * ~~ /\S/; # at least one non-space character
 has NonEmptyString $.name is rw;
 has NonEmptyString $.surname is rw;
 has Salary $.salary is rw;
 method gist {
 return qq:to[END];
 Name: $.name
 Surname: $.surname
 Salary: $.salary
 END
my $employee = Employee.new();
given $employee {
 .name = 'Sally';
 .surname = 'Ride';
 .salary = 200;
say $employee;
PHP.
在PHP中，可以使用表示实例的特殊变量$this返回当前对象。因此返回$this将使方法返回实例。下面的示例定义了一个Employee类和三个方法来设置它的名称、姓和薪水。每个Employee类的实例允许调用这些方法。
&lt;?php
class Employee
 public $name;
 public $surName; 
 public $salary;
 public function setName($name)
 $this-&gt;name = $name;
 return $this;
 public function setSurname($surname)
 $this-&gt;surName = $surname;
 return $this;
 public function setSalary($salary)
 $this-&gt;salary = $salary;
 return $this;
 public function __toString()
 $employeeInfo = 'Name: ' . $this-&gt;name . PHP_EOL;
 $employeeInfo .= 'Surname: ' . $this-&gt;surName . PHP_EOL;
 $employeeInfo .= 'Salary: ' . $this-&gt;salary . PHP_EOL;
 return $employeeInfo;
$employee = (new Employee())
 -&gt;setName('Tom')
 -&gt;setSurname('Smith')
 -&gt;setSalary('100');
echo $employee;
Python.
Python通过在实例方法中返回`self`：
class Poem(object):
 def __init__(self, content):
 self.content = content
 def indent(self, spaces):
 self.content = " " * spaces + self.content
 return self
 def suffix(self, content):
 self.content = self.content + " - " + content
 return self
»&gt; Poem("Road Not Travelled").indent(4).suffix("Robert Frost").content
' Road Not Travelled - Robert Frost'