出处: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



什么是流利语法Fluent Syntax的更多相关文章

  1. ES7: 展开语法spread syntax:

    第一次遇到: payload = {...payload, manufacturer: state.manufacturers.filter(x => x._id === payload.man ...

  2. shell脚本启动语法错误syntax error near unexpected token '{

    执行shell脚本时失败,报语法错误,但脚本内容检查正常 原因为该脚本是在非Linux系统下编辑之后放到系统执行的,文件模式类型非Linux系统匹配的模式类型. 查看文件的模式类型 显示文件的模式类型 ...

  3. Es6扩展运算符--三点运算符(...)--展开语法(Spread syntax)

    0.看文档呀 关于拓展运算符更详细的解释见 > MDN展开语法 关于剩余参数更详细的解释见 >MDN剩余参数 关于解构赋值更详细的解释见 >MDN解构赋值 直接看上面的文档更好 1. ...

  4. 高速上手Unity中最好的补间动画插件DFTween

     出处:http://blog.csdn.net/u010019717 author:孙广东      时间:2015.3.17   23:00 DFTween 是一个在 Unity 游戏引擎中高 ...

  5. LINQ 学习路程 -- 查询语法 LINQ Query Syntax

    1.查询语法 Query Syntax: from <range variable> in <IEnumerable<T> or IQueryable<T> ...

  6. LINQ教程二:LINQ操作语法

    LINQ查询时有两种语法可供选择:查询表达式语法(Query Expression)和方法语法(Fluent Syntax). 一.查询表达式语法 查询表达式语法是一种更接近SQL语法的查询方式. L ...

  7. LINQ之路 4:LINQ方法语法

    书写LINQ查询时又两种语法可供选择:方法语法(Fluent Syntax)和查询语法(Query Expression). LINQ方法语法是非常灵活和重要的,我们在这里将描述使用链接查询运算符的方 ...

  8. Linq学习(主要参考linq之路)----2LINQ方法语法

    方法语法:Fluent Syntax 方法语法是非常灵活和重要的.我们这里讲描述使用连接查询运算符的方式来创建复杂的子查询,方法语法的本质是通过扩展方法和Lambda表达式来创建查询. eg1: st ...

  9. C#语法之Linq查询基础一

    Linq做.Net开发的应该都用过,有些地方很复杂的逻辑用Linq很方便的解决.对于Linq to object.Linq to xml.Linq to sql.Linq to Entity(EF)都 ...

随机推荐

  1. C语言实现通用数据结构的高效设计

    近期在阅读一个开源的C++代码.里面用到了大量的STL里面的东西.或许是自己一直用C而非常少用C++来实现算法的原因.STL里面大量的模板令人心烦.一直对STL的效率表示怀疑,但在网上搜到这样一个帖子 ...

  2. MySQL分区技术 (一)

    4:MySQL 分区技术(是mysql 5.1以版本号后開始用->是甲骨文mysql技术团队维护人员以插件形式插入到mysql里面的技术) 眼下,针对海量数据的优化主要有2中方法: 1:大表拆成 ...

  3. 从零開始学android&lt;Menu菜单组件.三十.&gt;

    在Android系统之中.菜单一共同拥有三类:选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu). 今天我们就用几个样例来分别介绍下菜单的使用 acti ...

  4. Xcode 4.6.2 运行次数为偶数程序崩溃问题

    如果你的MAC 系统升级到10.8.4  Xcode升级到4.6.2,在工程运行第二次.第四次.第六次 ... 的时候程序就会崩溃 无论是新建的模板工程也会这样,这个属于系统BUG,在stackove ...

  5. c#常见stream操作

    原文: c#常见stream操作 常见并常用的stream一共有 文件流(FileStream), 内存流(MemoryStream), 压缩流(GZipStream), 加密流(CrypToStre ...

  6. OCP读书笔记(5) - 使用RMAN创建备份

    5.Creating Backups with RMAN 创建备份集 RMAN> backup as backupset format '/u01/app/oracle/backup/rmanb ...

  7. 《TCP/IP作品详细解释2:实现》笔记--Radix树路由表

    通过IP完整的路由是路由机制,它通过搜索路由表来确定从哪个分组被发送的接口执行此,它是不一样的路由策略,路由策略 它是一组规则,这些规则可以被用来确定哪些路由编程到路由表,Net/3内核实现的路由机制 ...

  8. hdu4521(线段树+dp)

    传送门:小明系列问题——小明序列 题意:有n个数,求间距大于d的最长上升序列. 分析:dp[i]表示在i点以a[i]结束距离大于d的最长上升序列,然后每更新到第i点时,取i-d之前小于a[i]的数为结 ...

  9. hdu2062(递推)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2062 详细分析:http://mamicode.com/info-detail-95273.html ...

  10. UVA 11100 The Trip, 2007 贪心(输出比较奇葩)

    题意:给出n个包的大小,规定一个大包能装一个小包,问最少能装成几个包. 只要排序,然后取连续出现次数最多的数的那个次数.输出注意需要等距输出. 代码: /* * Author: illuz <i ...