2010-06-17 112 views
17

僅僅是因爲動態類型,我們不需要python中的接口(如Java和C#)的概念?爲什麼我們不需要動態語言的接口?

+11

是的。 (填充剩餘空間達到15個字符) – Heinzi 2010-06-17 14:49:06

+0

我之前問過一個相關的問題。 http://stackoverflow.com/questions/2350968/should-i-define-interfaces-in-duck-typed-languages – 2010-06-17 15:14:34

+0

你怎麼知道我們需要什麼? – 2010-06-18 00:33:03

回答

23

作爲關鍵字和工件的interface是由Java (和C#從它那裏引入)來描述對象必須遵守的合同。

但是,接口一直是面向對象範式的關鍵部分,基本上它代表了對象必須響應的方法。 Java只是強制這種機制來提供靜態類型檢查。

因此,動態(OO)編程語言使用接口,甚至認爲他們不會靜態檢查它們。就像其他的數據類型,例如在紅寶石:

@i = 1; 

您不必申報類型的iFixNum你只需要使用它。接口也一樣,它們只是流動。權衡是,你不能對它進行靜態檢查,只能在運行時顯示故障。

另一方面Structural type(或者我稱之爲P的靜態鴨子類型)被Go或Scala等語言所使用,它給出了兩個世界中最好的東西。

1.見丹尼爾埃裏克約CORBA interface關鍵字

+2

如果可以的話,我會額外增加一個提及結構類型的+1。這是一個偉大的概念。 – RHSeeger 2010-06-17 15:35:13

+0

另一個用於結構打字的+1 – 2010-06-17 15:55:03

+3

「作爲關鍵字和工件的界面是由Java引入的」。不太確定。 CORBA的IDL(1991)具有'interface'關鍵字,在C++版本2.0(1989)中,具有所有純虛擬成員函數的類在語義上與接口相同。所以我猜想,也許Java從CORBA中借用了關鍵字,以便特別突出從C++借用的語言特性概念。 – 2010-06-17 16:07:44

0

接口用於靜態類型語言來描述兩個獨立的對象「實現相同的行爲」。在動態類型語言中,隱含地假設當兩個對象具有相同名稱/方法的參數時,它會做同樣的事情,所以接口是沒有用的。

0

在C#和Java註釋,接口都只是抽象類的所有抽象方法。它們存在允許僞多重繼承,而實際上不支持全面多重繼承和多重繼承創建的模糊性。

Python支持multiple inheritance,並有其自己的方式來確定在多個父項中存在方法時應該調用哪個父項的方法。

+0

「在C#和Java中,接口只是具有所有抽象方法的抽象類。」啊,如果那只是真的! http://smellegantcode.wordpress.com/2008/05/22/virtual-properties-in-c/ – 2010-06-17 16:11:54

1

在靜態類型語言中使用接口結構來教授類型系統在特定方法調用上下文中哪些對象可以互相替代。如果兩個對象實現相同的方法,但通過從通用基類的繼承或公共接口的實現不相關,則類型系統將在編譯時引發錯誤,如果您替換另一個。

動態語言使用「鴨子打字」,這意味着該方法只是在運行時查找,如果它存在與正確的簽名,它使用;否則會導致運行時錯誤。如果通過實施相同的方法,兩個對象都「像鴨子一樣呱呱叫」,它們是可替代的。因此,沒有明確的需要通過基類或接口將它們聯繫起來。

也就是說,作爲概念的界面在動態世界中仍然非常重要,但它們通常只是在文檔中定義,而不是由語言強制執行。有時候,我發現程序員實際上也爲此設計了一個基本類,它爲此畫出了界面;這有助於形式化文檔,並且如果接口的一部分可以用接口的其餘部分來實現,那麼它就特別有用。

5

我們不要要求他們,但我們做支持他們。檢查出Zope Interfaces(可以在Zope之外使用)。

0

動態語言鴨子類型化

如果它走起來像鴨子,叫起來 像鴨子,那麼它一定是鴨子

http://en.wikipedia.org/wiki/Duck_typing

換句話說,如果你執行一個對象來支持Delete()方法,而不是僅僅使用

obj.Delete() 

方法,但如果對象不支持Delete(),則會出現運行時錯誤。靜態類型的語言不會允許這樣做,並拋出編譯時錯誤。所以你基本上就是爲了更快的開發時間和靈活性而交易類型安全。

沒有接口,你可以做這樣的事情在靜態語言:

void Save(MyBaseClass item) 
{ 
    if (item.HasChanges) 
     item.Save() 
} 

但這需要您傳遞給此方法從MyBaseClass繼承每個對象。由於Java或C#不支持非常靈活的多層傳遞,因爲如果您的類已經繼承了另一個類,它也不能從MyBaseClass繼承。所以更好的選擇是創建一個ISavable接口並接受它作爲輸入參數以確保該項目可以被保存。那麼你就擁有了最好的兩個:類型安全性和靈活性。

public interface ISavable 
{ 
    bool HasChanges {get;set;} 
    void Save(); 
} 

void Save(ISavable item) 
{ 
    if (item.HasChanges) 
     item.Save() 
} 

如果你不能指望每個項目都會使用你的保存方法來實現接口,最後的後門是使用對象作爲參數。

void Save(object item) 
{ 
    if (item.HasChanges) 
     item.Save() 
} 

但不是再次,你沒有編譯時檢查,如果有人使用你的方法不兼容的類可能會得到一個運行時錯誤。

+0

「動態語言是Duck Typed」。這是一個非常瘋狂的事情要說。它不一定是完全正確的。 – 2010-06-18 06:42:03

1

值得注意的是,與許多人認爲的第一反應相反,接口可以用來做更多的事情,而不是文檔「一個類支持什麼方法」。 Grzenio用他的「實施同樣的行爲」的措辭來解決這個問題。作爲一個具體的例子,看一下Java接口Serializable。它沒有實現任何方法;而是將其用作「標記」來表示該類可以安全地序列化。

以這種方式考慮時,使用接口的動態語言可能是合理的。話雖如此,類似於註釋可能是一種更合理的方法。

1

至少有一些動態語言使得顯式接口不止一點尷尬的一個關鍵是動態語言通常可以對事先不知道的消息(err,「方法調用」)作出響應,甚至可以就像在飛行中創建方法一樣。知道對象是否會正確回覆消息的唯一方法是向消息發送消息。沒關係,因爲動態語言認爲能夠支持這種事情比靜態類型檢查更好;一個對象被認爲可用於特定的協議,因爲「已知」能夠參與該協議(例如,憑藉由另一個消息給出)。

+0

而「由另一條消息給出」我的意思是作爲參數傳遞給方法調用,或從方法調用返回。 – 2010-06-18 07:52:12

相關問題