出处: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. All consistent reads within the same transaction read the snapshot established by the first read.

    Session 1: Session 2: mysql> show variables like '%tx_isolation%'; +---------------+------------- ...

  2. Delphi 的绘图功能(29篇博客)

    http://www.cnblogs.com/del/category/123038.html

  3. UVALive 5791 Candy's Candy 解题报告

    比赛总结 题目 题意: 有f种口味的糖果,现在要把每颗糖果分到一些packs里面去.packs分两种: flavored pack:只有一种口味. variety pack:每种口味都有. 求满足下列 ...

  4. PHP SPL他们留下的宝石

    Rafael Dohms 上面的篇文章 让我为之惊艳,忍不住就翻译了下来,同一时候补充了部分内容. SPL,PHP 标准库(Standard PHP Library) ,此从 PHP 5.0 起内置的 ...

  5. python手记(46)

    #!/usr/bin/env python   # -*- coding: utf-8 -*- #http://blog.csdn.net/myhaspl   #code:myhaspl@qq.com ...

  6. ARM裸编程系列---UART

    S5PV210 UART说明 通用异步收发器缩写UART,这是UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER.它被用来传送串行数据.当发送数据,CPU将 ...

  7. CodeIgniter Apacheserver htaccess SEO重写写法

    1)支持重写 2)兼容全部APACHE server 3)假设不是文件,请求的结尾不包含反斜杠,自己主动跳转到反斜杠 4)文件名称 .htaccess 5)这个放到nginxserver怎么都不支持重 ...

  8. .Net 内存溢出(System.OutOfMemoryException)

    .Net 内存溢出(System.OutOfMemoryException) 在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾收集器又找不到任何可用内 ...

  9. php中遍历数组的方法

    参考网址:http://www.jb51.net/article/29949.htm 这三种方法中效率最高的是使用foreach语句遍历数组.从PHP4开始就引入了foreach结构,是PHP中专门为 ...

  10. Driver 初始化顺序

    Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有模块的程序编译到Linux内核中,由do_initcall函数加载 核心进程(/init/main.c)kernel_ini ...