duck typing java_编程语言中的鸭子类型 Duck Typing
來源 |?https://segmentfault.com/a/1190000019607240
1、什么是鴨子類型(duck typing)
百度百科是這樣解釋的:
這是程序設(shè)計(jì)中的一種類型推斷風(fēng)格,這種風(fēng)格適用于動(dòng)態(tài)語言(比如PHP、Python、Ruby、Typescript、Perl、Objective-C、Lua、Julia、JavaScript、Java、Groovy、C#等)和某些靜態(tài)語言(比如Golang,一般來說,靜態(tài)類型語言在編譯時(shí)便已確定了變量的類型,但是Golang的實(shí)現(xiàn)是:在編譯時(shí)推斷變量的類型),支持"鴨子類型"的語言的解釋器/編譯器將會(huì)在解析(Parse)或編譯時(shí),推斷對(duì)象的類型。
有沒有感覺很難理解?下面我們就來用通俗的語言介紹一下鴨子類型(Duck Typing)。
如果一只動(dòng)物走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只動(dòng)物就可以被稱為鴨子。
許多編程語言都支持 Duck Typing ,通常 Duck Typing 是動(dòng)態(tài)編程語言用來實(shí)現(xiàn)多態(tài)的一種方式。
在理解 Duck Typing 前,先看一張圖片,這是曾經(jīng)一度很火的大黃鴨
先問一個(gè)比較考三觀的問題:圖片中的大黃鴨,它是不是一只鴨子呢?
這個(gè)問題,得看你從哪個(gè)角度去看,如果從人們常識(shí)的認(rèn)知中的角度去看,它顯然不是一只鴨子,因?yàn)樗B最基本的生命都沒有。
但是從 Duck Typing 的角度來看,它就是一只鴨子!
Duck Typing 的原話是,走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么它就是一只鴨子。
這個(gè)原話是可以靈活理解的,就看我們?cè)趺炊x鴨子的行為,我們可以說,能浮在水上游的,黃色的,可愛的就是鴨子,那么,圖片中的大黃鴨,它就是一只鴨子!
這就是所謂的 Duck Typing,
它只關(guān)心事物的外部行為而非內(nèi)部結(jié)構(gòu)。它并不關(guān)心你這只鴨子是長(zhǎng)肉的還是充氣的。
在編程中,也常常用這種方式來描述事物。那么不同的編程語言中,Duck Typing 是怎么樣實(shí)現(xiàn)的呢?
1. Python 中的 Duck Typing
先看一個(gè)函數(shù):
def download(fetcher):
return fetcher.get("http://xxx");
有一個(gè) download 函數(shù),傳過來一個(gè) fetcher 參數(shù),fetcher 是可以獲取一個(gè) url 鏈接的資源的。
這個(gè) fetcher 就是一個(gè) Duck Typing 的對(duì)象,使用者約定好這個(gè) fetcher 會(huì)有一個(gè) get 函數(shù)就可以了。
顯然這個(gè) download 函數(shù)會(huì)有以下問題:
運(yùn)行時(shí)才知道傳入的 fetcher 有沒有 get 函數(shù)。那么站在 download 函數(shù)的使用者的角度上看,我怎么知道需要給 fetcher 實(shí)現(xiàn) get 方法呢?我不可能去閱讀 download 函數(shù)的代碼,實(shí)際情況中,可能 download 函數(shù)的代碼很長(zhǎng),可能 fetcher 不只要實(shí)現(xiàn) get 方法,還有其它方法需要實(shí)現(xiàn)。通常這種情況需要通過加注釋來說明。
2. C++ 中的 Duck Typing
C++ 不是動(dòng)態(tài)語言,但是它也能支持 Duck Typing,它是通過模板來支持的。
示例代碼:
template
string download(const F& fetcher){
return fetcher.get("http://xxxx")
}
這段代碼與 Python 的實(shí)現(xiàn)方法類似,這個(gè) fetcher 隨便什么類型都可以,只要實(shí)現(xiàn)一個(gè) get 方法,就能通過編譯。
那么這種實(shí)現(xiàn)方法有什么缺點(diǎn)呢,就是,編譯時(shí),才知道傳入的 fetcher 有沒有 get 方法。
但它比 python 好一點(diǎn)了,python 是運(yùn)行時(shí)才知道,C++ 是編譯時(shí)就知道。
同樣,這種情況,還是需要注釋來說明。
3. Java 中的類似代碼
Java 沒有 Duck Typing,它只有類似的代碼。Java 的 duck typing :
String download(F fetcher){
return fetcher.get("http://xxxx")
}
它同樣也用了模板類型。模板 F 必須 extends FetcherInterface ,有了這個(gè)限定,就能逼著 download 函數(shù)的使用者對(duì) fetcher 實(shí)現(xiàn) get 方法,它解決了需要注釋來說明的缺點(diǎn)。
傳入的參數(shù)必須實(shí)現(xiàn) FetcherInterface 接口,就沒有運(yùn)行時(shí)發(fā)現(xiàn)錯(cuò)誤,編譯時(shí)發(fā)現(xiàn)錯(cuò)誤的問題。
但是,它嚴(yán)格上來說不是 Duck Typing 。
如果 download 函數(shù)只依賴 fetcher 的 get 方法,而 FetcherInterface 接口必須要實(shí)現(xiàn)除 get 方法以外,還有其它方法,那么也要一一實(shí)現(xiàn),非常不靈活。
4. Go 中的 Duck Typing
在 Java 的 Duck Typing 類似代碼中,如果 fetcher 參數(shù)需要同時(shí)實(shí)現(xiàn)兩個(gè)或以上的接口方法時(shí),Java 是沒有辦法做到的。但 Go 語言可以做到。
type Fetcher interface {
Get(url string) string
}
type Saver interface {
Save(content string)
}
type FetcherAndSaver interface {
Fetcher
Saver
}
func download(f Fetcher) string {
return f.Get("http://xxxx")
}
func save(f saver) {
f.Save("some thing")
}
func downloadAndSave(f FetcherAndSaver) {
content := f.Get("http://xxxx")
f.Save(content)
}
# 實(shí)現(xiàn)者
type MyFetcherAndSaver struct {
}
func (f MyFetcherAndSaver) Get(url string) string {
...
}
func (f MyFetcherAndSaver) Save(content string) {
...
}
func main() {
f := MyFetcherAndSaver{}
download(f)
save(f)
downloadAndSave(f)
}
這里定義了三個(gè)接口,只要有 Get 方法的就是 Fetcher,只要有 Save 方法的就是 Saver,同時(shí)有 Get 方法和 Save 方法就是 FetcherAndSaver 。
實(shí)現(xiàn)者 MyFetcherAndSaver 并不需要聲明它實(shí)現(xiàn)了哪些接口,只要它有相關(guān)接口的所定義的方法,那么它的實(shí)例,就即能作為 Fetcher 接口來使用,又能作為 Saver 接口來使用,也能作為 FetcherAndSaver 接口來使用。
Go 的實(shí)現(xiàn)方法相對(duì)比較靈活,又不失類型檢查。總的來說,特點(diǎn)有:
即能同時(shí)實(shí)現(xiàn)多個(gè)接口
又具有 python , C++ 的 Duck Typing 靈活性
又具有 java 的類型檢查。
本文完~
總結(jié)
以上是生活随笔為你收集整理的duck typing java_编程语言中的鸭子类型 Duck Typing的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java实现自定义队列和树结构_Java
- 下一篇: windows xp安装php7,在Wi