[JavaScript,Java,C#,C++,Ruby,Perl,PHP,Python][转]流式接口(Fluent interface)
原文:https://en.m.wikipedia.org/wiki/Fluent_interface(英文,完整)
转载:https://zh.wikipedia.org/wiki/流式接口(中文,部分翻译,部分例子,破墙)
流式接口(fluent interface)是软件工程中面向对象API的一种实现方式,以提供更为可读的源代码。最早由Eric Evans与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<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());
流式接口可用于一系列方法,他们运行在同一对象上。
// Defines the data context
class Context
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sex { get; set; }
public string Address { get; set; }
} 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 & 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;
}
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(, ); // Set window params
app.setWindowPosition(, );
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(, ).across(, )
.named("My OpenGL/GLUT App")
.create();
}
Ruby
Ruby语言允许修改核心类,这使得流式接口成为原生易于实现。
# Add methods to String class
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 # Fluent interface
message = "there"
puts message.prefix("hello")
.suffix("world")
.indent(8)
Perl 6
In Perl 6, there are many approaches, but one of the simplest is to declare attributes as read/write and use the given 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 * > ;
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 = ;
} say $employee; # Output:
# Name: Sally
# Surname: Ride
# Salary: 200
PHP
In PHP, one can return the current object by using the $this special variable which represent the instance. Hence return $this; will make the method return the instance. The example below defines a class Employee and three methods to set its name, surname and salary. Each return the instance of the Employee class allowing to chain methods.
<?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, Tom Smith, with a salary of 100:
$employee = (new Employee())
->setName('Tom')
->setSurname('Smith')
->setSalary('100'); # Display the value of the Employee instance:
echo $employee; # Display:
# Name: Tom
# Surname: Smith
# Salary: 100
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
>>> Poem("Road Not Travelled").indent(4).suffix("Robert Frost").content
' Road Not Travelled - Robert Frost'
[JavaScript,Java,C#,C++,Ruby,Perl,PHP,Python][转]流式接口(Fluent interface)的更多相关文章
- python 使用流式游标 读取mysql怎么不会内存溢出
使用过java读取mysql大数据量的人应该都知道,如果查询时不开游标不设置一次性区大小的话,会一次性的把所有记录都拉取过来再进行后续操作,数据量一大就很容易出现OOM 如果用python去读取mys ...
- java mysql大数据量批量插入与流式读取分析
总结下这周帮助客户解决报表生成操作的mysql 驱动的使用上的一些问题,与解决方案.由于生成报表逻辑要从数据库读取大量数据并在内存中加工处理后在 生成大量的汇总数据然后写入到数据库.基本流程是 读取- ...
- Faust——python分布式流式处理框架
摘要 Faust是用python开发的一个分布式流式处理框架.在一个机器学习应用中,机器学习算法可能被用于数据流实时处理的各个环节,而不是仅仅在推理阶段,算法也不仅仅局限于常见的分类回归算法,而是会根 ...
- Python接受流式输入
随笔记录——Python接受终端入若干行输入 Python接受终端的若干行输入时,比较常用的input()不再好用. 1. 导入sys模块: import sys 2. for循环接受输入: for ...
- 常用脚本语言Perl,Python,Ruby,Javascript一 Perl,Python,Ruby,Javascript
常用脚本语言Perl,Python,Ruby,Javascript一 Perl,Python,Ruby,Javascript Javascript现阶段还不适合用来做独立开发,它的天下还是在web应用 ...
- Perl,Python,Ruby,Javascript 四种脚本语言比较
Perl 为了选择一个合适的脚本语言学习,今天查了不少有关Perl,Python,Ruby,Javascript的东西,可是发现各大阵营的人都在吹捧自己喜欢的语言,不过最没有争议的应该是Javascr ...
- 正则表达式匹配可以更快更简单 (but is slow in Java, Perl, PHP, Python, Ruby, ...)
source: https://swtch.com/~rsc/regexp/regexp1.html translated by trav, travmymail@gmail.com 引言 下图是两种 ...
- JSP,PHP,Python,Ruby,Perl概要及各自特点
JSP,PHP,Python,Ruby,Perl概要及各自特点 博客分类: JSP PHP Python Ruby Perl概要及各自特点 javascript 互联网技术日新月异,编程的语言层出不 ...
- C,C++,Lisp,Java,Perl,Python
(译注:圣经记载:在远古的时候,人类都使用一种语言,全世界的人决定一起造一座通天的塔,就是巴别塔,后来被上帝知道了,上帝就让人们使用不同的语言,这个塔就没能造起来. 巴别塔不建自毁,与其说上帝的分化将 ...
随机推荐
- XSS学习(三)挖掘思路
HTML标签之间 <div id="body"> [输出点] </div> payload:<script>alert(1)</scrip ...
- java基础(三):反射、反序列化破解单列模式和解决方式
单例模式指的是一个类只有一个对象,通过一些措施达到达到这个目的.但是反射和反序列化可以获得多个不同的对象. 先简单的认识一下单例模式 一:单例模式 通过私有构造器,声明一个该类的静态对象成员,提供一个 ...
- Java技术之如何保证同一资源被多个线程并发访问时的完整性?
常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问.Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持. 在Java中一共有四种方法支持同步,其中前三个是同步 ...
- MySQL数据库使用规范
一.建表规约 1.[强制]表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint (1表示是,0表示否) 说明:任何字段如果为非负数,必须是unsigned ...
- ES6新增的数据类型Map和Set。
Javascript的默认对象表示方式 {} ,即一组键值对. 但是Javascript的对象有个小问题,就是键必须是字符串.但实际上Number或者其他数据类型作为键也是非常合理的. 为了解决这个问 ...
- Java高级特性 第7节 多线程
一.进程与线程的概念 1. 进程 进程是应用程序的执行实例,有独立的内存空间和系统资源. 如上图,标红色的是一个Office Word进程. 进程的特点: 动态性:进程是动态的创建和消亡: 并发性:操 ...
- Log4j源码分析
一.slf4j和log4j的关系: 也就是说slf4j仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已.必须搭配具体的log实现方案比 ...
- 1、Nexus安装
1.nexus 下载地址: https://sonatype-download.global.ssl.fastly.net/nexus/oss/nexus-2.14.5-02-bundle.tar.g ...
- mvc项目远程发布到windows server服务器
1.安装IIS的时候需要将这两个选项勾选起来 2.确保 管理服务委派 这个选项存在 3.添加委派规则 4.配置IIS管理用户,后续需要用这个用户进行发布连接 5.配置站点的IIS权限 选择刚才在前面设 ...
- 记一个在移动端调试 web 页面的方法
1. 工具:Weinre 2. 安装:npm -g install weinre | npm install weinre -g --registry=https://registry.npm.tao ...