出处:http://blog.csdn.net/u010019717
author:孙广东 时间:2015.3.18 23:00
编程新概念:什么是流利语法fluent syntax?
首先感谢 unity的一款插件 DFTween (内容例如以下http://blog.csdn.net/u010019717/article/details/44359119),通过学习它知道了流利语法的概念。
Fluent interface连贯接口
在软件project,一种Fluent interface连贯接口(作为首先由Eric Evans和MartinFowler创造)是面向对象的API,旨在提供更具可读性的代码运行。
Fluent interface通常通过使用methodcascading方法级联(具体methodchaining方法链接)中context指令连续调用运行 (但Fluent interface须要不不过方法链接)。通常context上下文是 :
·定义通过返回值(类对象)调用方法
·以自我作为參照,在新的背景下是相当于最后一个context上下文
·通过返回一个void的上下文终止。
内容
1 History
2 Examples
2.1 JavaScript
2.2 Java
2.3 C++
2.7 PHP
2.8 C#
2.9 Python
历史
术语"Fluent interface"是在 2005 年年底提出,尽管这样的interface面的总体风格追溯到 1970 年代,Smalltalk 在级联的方法被发明,在上世纪 80 年代的很多样例。最熟悉的是在 c + +,使用iostream库<<或>> 运算符为消息传递、将多个数据发送到同一个对象和其它方法调用同意"manipulators"。
样例
JavaScript
有非常多使用几种变体的 JS 库的样例:可能是最广为人知的 jQuery。通经常使用fluent builders流利的建设者来实现 'DB 查询',比如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 中使用prototype inheritance原型继承和 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();
更通用的方式做到这一点是在mu-ffsm中实现.
var mkChained = function(spec) { return function(init) { var s = spec[0] ? spec[0](init) : 0; var i = function(opt) { return spec[1] ? spec[1](s, opt) : s; } Object.keys(spec).forEach( function(name){ // skip `entry` and `exit` functions if(/^\d+$/.test(name)) return; // transition 'name : (s, opt) -> s' i[name] = function(opt) { s = spec[name](s, opt); return i; }; }); return i; } }; var API = mkChained({ 0: function(opt) {return ;/* create initial state */}, then: function(s, opt) {return s; /* new state */}, whut: function(s, opt) {return s; /* new state */}, 1: function(s, opt) {return ;/* compute final value */} }); // We create an instance of our newly crafted API, var call = API() // entry .whut() // transition .then() // transition .whut(); // transition // And call it var result0 = call() // exit , result1 = call() // exit
Java
JOOQ型号的库作为 fluent API 在 Java 中的 SQL
Author a = AUTHOR.as("a"); create.selectFrom(a) .where(exists(selectOne() .from(BOOK) .where(BOOK.STATUS.eq(BOOK_STATUS.SOLD_OUT)) .and(BOOK.AUTHOR_ID.eq(a.ID))));
Op4j库使fluent流畅代码,用于运行辅助任务结构迭代、 数据转换、 过滤等。
String[] datesStr = new String[] {"12-10-1492", "06-12-1978"}; ... List<Calendar> dates = Op.on(datesStr).toList().map(FnString.toCalendar("dd-MM-yyyy")).get();
Fluflu凝视处理器能够使用 Java 凝视 fluent API创建。
JaQue使 Java 8 lambda 时必须表示为表达式文件夹树在运行时,使它能够即创建类型安全连贯接口,而不是窗口中的对象:
Customer obj = ... obj.property("name").eq("John") 一种学法: method<Customer>(customer -> customer.getName() == "John")
C + +
C + +中,一个fluentinterface常见用途是的标准iostream,当中链重载的运算符.
以下是提供在更传统的界面,在 c + + 中的fluent interface包装程序的演示样例:
// 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(); } }; // 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(); }
PHP
在 PHP 中,一个人能够通过使用$this 特殊的变量所表示的实例返回当前对象。因此返回 $this ;将使返回的实例的方法。以下的演示样例定义一个类Employee和三种方法来设置其name, surname 和 salary。每一个返回Employee类同意对链方法的实例。
<?php class Employee { public $name; public $surName; public $salary; public function setName($name) { $this->name = $name; return $this; } public function setSurname($surname) { $this->surName = $surname; return $this; } public function setSalary($salary) { $this->salary = $salary; return $this; } public function __toString() { $employeeInfo = 'Name: ' . $this->name . PHP_EOL; $employeeInfo .= 'Surname: ' . $this->surName . PHP_EOL; $employeeInfo .= 'Salary: ' . $this->salary . PHP_EOL; return $employeeInfo; } } # Create a new instance of the Employee class: $employee = new Employee(); # Employee Tom Smith has a salary of 100: echo $employee->setName('Tom') ->setSurname('Smith') ->setSalary('100'); # Display: # Name: Tom # Surname: Smith # Salary: 100
C#
C# 使用fluent在LINQ中广泛编程来生成使用标准查询运算符的查询。基于扩展方法.
var translations = new Dictionary<string, string> { {"cat", "chat"}, {"dog", "chien"}, {"fish", "poisson"}, {"bird", "oiseau"} }; // Find translations for English words containing the letter "a", // sorted by length and displayed in uppercase IEnumerable<string> query = translations .Where (t => t.Key.Contains("a")) .OrderBy (t => t.Value.Length) .Select (t => t.Value.ToUpper()); // The same query constructed progressively: var filtered = translations.Where (t => t.Key.Contains("a")); var sorted = filtered.OrderBy (t => t.Value.Length); var finalQuery = sorted.Select (t => t.Value.ToUpper()); Fluent interface也能够用于链设置方法,当中operates/shares同样的对象。而不是创建一个customer类我们能够创建一个data context数据上下文,能够用fluent interface,例如以下所看到的: //defines the data context class Context { public string fname { get; set; } public string lname {get; set;} public string sex { get; set; } public string address { get; set; } } //defines the customer class class Customer { Context context = new Context(); //initializes the context // set the value for properties public Customer FirstName(string firstName) { context.fname = firstName; return this; } public Customer LastName(string lastName) { context.lname = 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.fname,context.lname,context.sex,context.address); } } class Program { static void Main(string[] args) { //object creation Customer c1 = new Customer(); //using the method chaining to assign & print data with a single line c1.FirstName("vinod").LastName("srivastav").Sex("male").Address("bangalore").Print(); } }
Python
在 Python 返回 'self' 中的实例方法是实现fluent pattern的一种方法。
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 Poem("Road Not Travelled").indent(4).suffix("Robert Frost").content ' Road Not Travelled - Robert Frost'
更具体的内容观看*:https://en.wikipedia.org/wiki/Fluent_interface