流畅的界面和漏洞抽象

时间:2009-01-11 19:11:49

标签: oop fluent-interface leaky-abstraction

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

另外,什么是漏洞抽象?

由于

8 个答案:

答案 0 :(得分:26)

流畅的界面是一种API,允许您编写与普通英语大致相同的代码。例如:

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

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

  

我也注意到了一个常见的误解 - 许多人似乎将流畅的界面与Method Chaining等同起来。当然链接是一种常用的技术,可以使用流畅的界面,但真正的流畅性远不止于此。

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

答案 1 :(得分:18)

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

All abstractions lie或多或少,但有时抽象与潜在的现实非常不符合,它会带来更多的伤害而不是它的帮助。

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

答案 2 :(得分:9)

一个流畅的界面,一个术语埃里克埃文斯创造,它只是方法链的另一个名称。 Martin Fowler在这个问题上写了couple articles,但它大致如下:

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

Fluent界面通常用于以不支持它们的语言(例如C ++中的命名参数惯例)或域特定语言创建命名参数,以使代码读取更流畅。

我已经看到它们被用于从图像处理库到正则表达式库,3D库的所有内容。其他示例包括树结构,列表或其他数据结构的构造。需要构建复杂对象(参数加载)的所有内容都可以使用Fluent接口使其更具可读性。例如,将前面的示例与CreateWindow函数调用进行比较:

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

答案 3 :(得分: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,即使它是有效的结果。

答案 4 :(得分:3)

面向对象的界面流利如果方法执行副作用返回self ,那么这些方法可以链接在一起。

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

答案 5 :(得分:1)

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

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

public City GetCity(string zipCode)
{
   zipCode.Assert("zipCode").IsNotNullOrEmpty().HasLength(5,10).Matches("\\d[5]-\\d[4]");
   // Continue processing
}
但是,我不能谈论漏洞抽象。

答案 6 :(得分:1)

谢谢你们。

很棒的描述。

我想到了流畅的界面,它们是为了便于阅读。我总是可以阅读一系列方法,以及如何与上一个/下一个方法相关。

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

答案 7 :(得分:1)

Neal Ford在他的“生产程序员”一书中解释并提供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);
相关问题