2009-01-11 46 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);