13

什么是流畅的界面?我找不到一个好的定义,但我得到的只是我不太熟悉的语言(例如 C++)的长代码示例。

另外,什么是泄漏抽象?

谢谢

4

8 回答 8

27

流利的界面是一种 API,它允许您编写读起来或多或少像普通英语的代码。例如:

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

方法链通常用作实现的一部分,但不止于此。引用福勒的话:

我还注意到一个常见的误解——许多人似乎将流畅的接口等同于方法链。当然,链接是与流畅接口一起使用的常用技术,但真正的流畅性远不止于此。

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

于 2009-01-11T19:57:49.187 回答
18

泄漏抽象是底层现实的细节经常“泄漏”的抽象。

所有的抽象都或多或少地存在,但有时抽象与潜在的现实是如此不匹配,以至于它造成的伤害大于它的帮助。

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

于 2009-01-11T20:22:28.373 回答
9

A fluent interface a term Eric Evans coined and it's just another name for method chaining. Martin Fowler wrote a couple of articles on this subject, but it roughly looks like this:

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

Fluent interface are generally used to create named parameters in a language that doesn't support them (the Named Parameter Idiom in C++ for example), or in Domain Specific Languages to make the code read more fluently.

I've seen them being used for everything from image processing libraries, to regular expression libraries, 3D libraries. Other examples include the construction of tree structures, lists, or other datastructures. Everything that requires the construction of complex objects (load of parameters) can make use of Fluent Interfaces to make it more readable. For example, compare the previous example to the CreateWindow function call:

 ::CreateWindow(
      "Window class", 
      "Window title", 
      dwStyle, X, Y, 
      nWidth, nHeight, 
      hWndPant, hMenu, 
      hInstance, NULL
 );
于 2009-01-11T19:24:01.127 回答
5

Here's a regular every-day interface:

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

And here's a fluent interface:

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

The most obvious difference is that when we return a void, we return instead an instance of the interface type. What's understood is that the interface returned is the CURRENT INSTANCE, not a new instance of the same type. Of course, this isn't enforceable, and in the case of immutable objects (like string) it is a different instance but can be considered to be the same instance only updated.

Here are examples of their use:

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

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

Notice that the fluent interface is easier to use when chaining different calls. IRL, check out the Linq extension methods and how each call is designed to flow into another. None of the methods return void, even if it would be a valid result.

于 2009-01-11T19:27:24.037 回答
3

如果为副作用而执行的方法返回,则面向对象的接口是流畅的,因此可以将这些方法链接在一起。self

我第一次遇到流畅的接口是在 1990 年,当时 Modula-3 接口警察(我没有编造这个)要求所有初始化方法返回已初始化的对象。我相信这种用法早于“流畅界面”一词的诞生。

于 2009-01-11T20:14:07.420 回答
1

多谢你们。

很棒的描述。

我对流畅接口的想法是为了可读性。我总是可以阅读一系列方法以及其中一个方法与上一个/下一个方法的关系。

例如,就像发布验证示例的发帖人(我已经编写了与之前类似的代码)。

于 2009-01-11T21:41:26.823 回答
1

In a fluent interface, a object's methods will return a reference to the object, so that you can chain the method calls together.

For example, in NValidate, I did this to simplify parameter validation:

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

I can't speak to leaky abstractions, though.

于 2009-01-11T19:28:53.597 回答
1

Neal Ford在他的“Productive Programmer”一书中很好地解释并给出了 Fluent Interface 示例。

带有 getter/setter 的传统对象或“bean”:

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);
于 2009-07-07T01:57:58.237 回答