2009-01-11 140 views
13

什么是流畅的接口?我找不到一个好的定义,但我所得到的只是一个我不太熟悉的语言(例如C++)中的长代码示例。流畅的接口和泄漏抽象

另外,什么是漏泄抽象?

感谢

+1

这应该作为两个单独的问题发布。 – 2013-07-09 14:40:11

回答

9

说一口流利的界面术语埃里克埃文斯创造的,它是方法链的另一个名称。 Martin Fowler的关于这个主题写的articles一个couple,但它大致是这样的:

m_Window = window::with() 
    .width(l_Width) 
    .height(l_Height) 
    .title("default window") 
    .left(200) 
    .top(200) 
.create(); 

流利的接口通常用于在不支持他们(命名参数成语在C语言创建命名参数++例如)或域特定语言中,以使代码更流利。

我已经看到它们用于从图像处理库到正则表达式库,3D库的所有内容。其他示例包括树结构,列表或其他数据结构的构建。所有需要构建复杂对象(参数负载)的应用程序都可以使用Fluent接口来提高可读性。例如,在前面的例子比较的CreateWindow函数调用:

::CreateWindow(
     "Window class", 
     "Window title", 
     dwStyle, X, Y, 
     nWidth, nHeight, 
     hWndPant, hMenu, 
     hInstance, NULL 
); 
+0

像jQuery的链接? – 2009-01-11 19:25:15

+0

我从事过任何与网络相关的开发已经有一段时间了,但从jQuery文档来看,它似乎是这样。 – 2009-01-11 19:33:58

+0

这是方法链接,而不是流畅的接口。请参阅上面Rasmus的回答*“当然,链接是流畅界面使用的常用技术,但真正的流畅度远不止于此......”* – Pacerier 2015-08-13 11:22:47

5

这是一个普通的每一天接口:

public interface NotFluent 
{ 
    void DoA(); 
    void DoB(); 
    void DoC(); 
} 

而且这里有一个流畅的接口:

public interface Fluent 
{ 
    Fluent DoA(); 
    Fluent DoB(); 
    Fluent DoC(); 
} 

最明显的区别在于,当我们返回一个void时,我们返回一个接口类型的实例。所理解的是返回的接口是CURRENT INSTANCE,而不是同一类型的新实例。当然,这是不可强制执行的,而且在不可变对象(如字符串)的情况下,它是不同的实例,但可以被认为是仅更新的相同实例。

这里是他们使用的例子:

NotFluent foo = new NotFluentImpl(); 
foo.DoA(); 
foo.DoB(); 
foo.DoC(); 

Fluent bar = new FluentImpl(); 
bar.DoA().DoB().DoC(); 

注意,流畅的接口更容易链接不同的呼叫时使用。 IRL,检查Linq扩展方法以及每个调用如何设计流入另一个。没有任何方法返回void,即使它是有效的结果。

+0

这个示例不是简单的方法链吗?福勒指出[*“许多人似乎将流畅的界面等同于方法链接”(http://www.martinfowler.com/bliki/FluentInterface.html)。上面的代码具有哪些属性,使其成为流畅的界面而不仅仅是方法链接? – Pacerier 2015-08-13 11:28:49

1

在流畅的界面中,对象的方法将返回对该对象的引用,以便您可以将方法调用链接在一起。

例如,在NValidate,我这样做是为了简化参数验证:

public City GetCity(string zipCode) 
{ 
    zipCode.Assert("zipCode").IsNotNullOrEmpty().HasLength(5,10).Matches("\\d[5]-\\d[4]"); 
    // Continue processing 
} 

我不能说对泄漏的抽象,虽然。

24

一个流畅的界面是一个API,它允许你编写或多或少像普通英语一样的代码。例如:

Find.All.Questions(Where.IsAnswered == true); 

方法链通常用作实现的一部分,但除此之外还有更多。引用Fowler

我也注意到了一个常见的误解 - 许多人似乎把流畅的接口等同于方法链接。当然,链接是流畅界面使用的常用技术,但真正的流畅度远不止于此。

它也经常被称为内部DSL,因为语法类似于一个DSL的,但它的宿主语言,而不是由一个解析器正在处理内部实现。

3

面向对象的接口是流利如果了为副作用返回self执行的方法,从而使这种方法可以链接在一起。

1990年,我第一次遇到流畅的接口,当Modula-3接口警察(我没有做这件事)需要所有的初始化方法返回初始化的对象。我相信这个用法早于术语“流畅界面”的造币。

17

漏泄抽象是一种抽象,其中底层现实的细节经常“泄漏”。

All abstractions lie或多或少的,但有时抽象是不适合潜在的现实,这是造成更多的伤害,而不是帮助。

抽象中“泄漏”的一个简单示例可能是通常的浮点类型。它似乎代表一般的实数,你可以用它来执行基本的计算。但是在某个时候,您会遇到1/3 * 3!= 1或1 + 10^-20 = 1的情况。这是实际实现细节泄露并且抽象中断的时候。

1

谢谢你们。

很好的描述。

我对流畅接口的想法是为了便于阅读。我总是可以阅读一连串的方法,以及如何与上一个/下一个方法相关。

E.g.像发布验证示例的海报(我已经编写了类似于之前的代码)。

1

Neal Ford在他的书'Productive Programmer'中做了一个很好的解释和给出Fluent接口示例的工作。

传统的对象或“豆”的getter/setter方法:

Car car = new CarImpl(); 
MarketingDescription des = new MarketingDescriptionImpl(); 
desc.setType("Box"); 
desc.setSubtype("Insulated"); 
desc.setAttribute("length", "50.5"); 
desc.setAttribute("ladder", "yes"); 
desc.setAttribute("lining type", "cork"); 
car.setDescription(desc); 

满足同样需要有一个流畅的接口:

Car car = Car.describedAs() 
    .box() 
    .length(50.5) 
    .type(Type.INSULATED) 
    .includes(Equipment.LADDER) 
    .lining(Lining.CORK);