出处: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. How to Design Programs, Second Edition

    How to Design Programs, Second Edition How to Design Programs, Second Edition

  2. 由一道淘宝面试题到False sharing问题

    今天在看淘宝之前的一道面试题目,内容是 在高性能服务器的代码中经常会看到类似这样的代码: typedef union { erts_smp_rwmtx_t rwmtx; byte cache_line ...

  3. qt qml中PropertyAnimation的几种使用方法

    qml文章 qt qml中PropertyAnimation的几种使用方法 动画应用场景有以下几种: 首先如果一个Rectangle.动画是要改变它的x和y值 1,Rectangle一旦被创建,就要移 ...

  4. Delphi 类与对象内存结构浅析(三篇)

    http://blog.csdn.net/starsky2006/article/details/5497082 http://blog.csdn.net/starsky2006/article/de ...

  5. SuSE(SLES)安装配置syslog-ng日志server,可整合splunk

    Update History 2014年04月25日 - 撰写初稿 引言 在自己主动化部署AutoYast.自己主动化监控BMC Patrol双方面形成雏形后.日志的收集.管理.分析也顺势成为我们须要 ...

  6. POJ3071-Football(概率DP+滚动数组)

    Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2769   Accepted: 1413 Descript ...

  7. 从零開始学习制作H5应用——V5.0:懊悔机制,整理文件夹,压缩,模板化

    经过前面四个版本号的迭代.我们已经制作了一个从视觉和听觉上都非常舒服的H5微场景应用,没有看过的请戳以下: V1.0--简单页面滑动切换 V2.0--多页切换.透明过渡及交互指示 V3.0--增加lo ...

  8. 【IOS实例小计】今日开贴,记录我的ios学习生涯,留下点滴,留下快乐,成荫后人。

    今天开贴来记录自己的ios学习过程,本人目前小白一个,由于对ios感兴趣,所以开始学习,原职java程序,呵呵,勿喷. 本次的[ios实例小计]主要参考一文http://blog.sina.com.c ...

  9. leetcode第一刷_Permutations II

    当有反复元素的时候呢? 不用拍脑袋都会想到一种方法,也是全部有反复元素时的通用处理方法,维护一个set,假设这个元素没增加过就增加,增加过了的忽略掉.可是,在这道题上这个通用方法竟然超时了! 怎么办? ...

  10. hadoop学习;大数据集在HDFS中存为单个文件;安装linux下eclipse出错解决;查看.class文件插件

    sudo apt-get install eclipse 安装后打开eclipse,提示出错 An error has occurred. See the log file /home/pengeor ...