新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「 crossoverJie」,作者 crossoverJie。轉(zhuǎn)載本文請(qǐng)聯(lián)系 crossoverJie公眾號(hào)。

十年的榆中網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。營(yíng)銷型網(wǎng)站的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整榆中建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“榆中網(wǎng)站設(shè)計(jì)”,“榆中網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
前言
”面向接口編程“寫 Java 的朋友耳朵已經(jīng)可以聽(tīng)出干繭了吧,當(dāng)然這個(gè)思想在 Java 中非常重要,甚至幾乎所有的編程語(yǔ)言都需要,畢竟程序具有良好的擴(kuò)展性、維護(hù)性誰(shuí)都不能拒絕。
最近無(wú)意間看到了我剛開始寫 Python 時(shí)的部分代碼,當(dāng)時(shí)實(shí)現(xiàn)的需求有個(gè)很明顯的特點(diǎn):
- 不同對(duì)象具有公共的行為能力,但具體每個(gè)對(duì)象的實(shí)現(xiàn)方式又各不相同。
說(shuō)人話就是商戶需要接入平臺(tái),接入的步驟相同,但具體實(shí)現(xiàn)不同。
作為一個(gè)”資深“ Javaer,需求還沒(méi)看完我就洋洋灑灑的把各個(gè)實(shí)現(xiàn)類寫好了:
當(dāng)然最終也順利實(shí)現(xiàn)需求,甚至把組里一個(gè)沒(méi)寫過(guò) Java 的大哥唬的一愣一愣的,直呼牛逼。
不過(guò)事后也給我吐槽:
- 你這設(shè)計(jì)是不錯(cuò),但是感覺(jué)好復(fù)雜,跟代碼時(shí)要找到真正的業(yè)務(wù)邏輯(實(shí)現(xiàn)類)得繞幾圈。
截止目前 Python 寫多了,我總算是能總結(jié)他的感受:就是不夠 Pythonic。
雖說(shuō) Python 沒(méi)有類似 Java 這樣的 Interface 特性,但作為面向?qū)ο蟮母呒?jí)語(yǔ)言也是支持繼承的;
在這里我們也可以利用繼承的特性來(lái)實(shí)現(xiàn)面向接口編程:
- class Car:
- def run(self):
- pass
- class Benz(Car):
- def run(self):
- print("benz run")
- class BMW(Car):
- def run(self):
- print("bwm run")
- def run(car):
- car.run()
- if __name__ == "__main__":
- benz = Benz()
- bmw = BMW()
- run(benz)
- run(bmw)
代碼非常簡(jiǎn)單,在 Python 中也沒(méi)有類似于 Java 中的 extends 關(guān)鍵字,只需要在類聲明末尾用括號(hào)包含基類即可。
這樣在每個(gè)子類中就能單獨(dú)實(shí)現(xiàn)業(yè)務(wù)邏輯,方便擴(kuò)展和維護(hù)。
類型檢查
由于 Python 作為一個(gè)動(dòng)態(tài)類型語(yǔ)言,無(wú)法做到 Java 那樣在編譯期間校驗(yàn)一個(gè)類是否完全實(shí)現(xiàn)了某個(gè)接口的所有方法。
為此 Python 提供了解決辦法,那就是 abc(Abstract Base Classes) ,當(dāng)我們將基類用 abc 聲明時(shí)就能近似做到:
- import abc
- class Car(abc.ABC):
- @abc.abstractmethod
- def run(self):
- pass
- class Benz(Car):
- def run(self):
- print("benz run")
- class BMW(Car):
- pass
- def run(car):
- car.run()
- if __name__ == "__main__":
- benz = Benz()
- bmw = BMW()
- run(benz)
- run(bmw)
一旦有類沒(méi)有實(shí)現(xiàn)方法時(shí),運(yùn)行期間便會(huì)拋出異常:
- bmw = BMW()
- TypeError: Can't instantiate abstract class BMW with abstract methods run
雖然無(wú)法做到在運(yùn)行之前(畢竟不需要編譯)進(jìn)行校驗(yàn),但有總比沒(méi)有好。
鴨子類型
以上兩種方式看似已經(jīng)畢竟優(yōu)雅的實(shí)現(xiàn)面向接口編程了,但實(shí)際上也不夠 Pythonic。
在繼續(xù)之前我們先聊聊接口的本質(zhì)到底是什么?
在 Java 這類靜態(tài)語(yǔ)言中面向接口編程是比較麻煩的,也就是我們常說(shuō)的子類向父類轉(zhuǎn)型,因此需要編寫額外的代碼。
帶來(lái)的好處也是顯而易見(jiàn),只需要父類便可運(yùn)行。
但我們也不必過(guò)于執(zhí)著于接口,它本身只是一個(gè)協(xié)議、規(guī)范,并不特指 Java 中的 Interface,甚至有些語(yǔ)言壓根沒(méi)有這個(gè)關(guān)鍵字。
動(dòng)態(tài)語(yǔ)言的特性也不需要強(qiáng)制校驗(yàn)是否實(shí)現(xiàn)了方法。
在 Python 中我們可以利用鴨子類型來(lái)優(yōu)雅的實(shí)現(xiàn)面向接口編程。
在這之前先了解下鴨子類型,借用維基百科的說(shuō)法:
- “當(dāng)看到一只鳥走起來(lái)像鴨子、游泳起來(lái)像鴨子、叫起來(lái)也像鴨子,那么這只鳥就可以被稱為鴨子?!?/li>
我用大白話翻譯下就是:
即便兩個(gè)完全不想干的類,如果他們都實(shí)現(xiàn)了相同的方法,那就可以把他們當(dāng)做同一類型的類來(lái)使用。
舉個(gè)簡(jiǎn)單例子:
- class Order:
- def create(self):
- pass
- class User:
- def create(self):
- pass
- def create(obj):
- obj.create()
- if __name__ == "__main__":
- order = Order()
- user = User()
- create(order)
- create(user)
這里的 order 和 user 本身完全沒(méi)有關(guān)系,只是他們都有相同方法,又得益于動(dòng)態(tài)語(yǔ)言沒(méi)法校驗(yàn)類型的特點(diǎn),所以完全可以在運(yùn)行的時(shí)候認(rèn)為他們是同一種類型。
因此基于鴨子類型,之前的代碼我們可以稍作簡(jiǎn)化:
- class Car:
- def run(self):
- pass
- class Benz:
- def run(self):
- print("benz run")
- class BMW:
- def run(self):
- print("bwm run")
- def run(car):
- car.run()
- if __name__ == "__main__":
- benz = Benz()
- bmw = BMW()
- run(benz)
- run(bmw)
因?yàn)樵邙喿宇愋椭形覀冊(cè)谝獾氖撬男袨?,而不是他們的類?所以完全可以不用繼承便可以實(shí)現(xiàn)面向接口編程。
總結(jié)
我覺(jué)得平時(shí)沒(méi)有接觸過(guò)動(dòng)態(tài)類型語(yǔ)言的朋友,在了解完這些之后會(huì)發(fā)現(xiàn)新大陸,就像是 Python 老手第一次使用 Java 時(shí);雖然覺(jué)得語(yǔ)法啰嗦,但也會(huì)羨慕它的類型檢查、參數(shù)驗(yàn)證這類特點(diǎn)。
動(dòng)靜語(yǔ)言之爭(zhēng)這里不做討論了,各有各的好,鞋好不好穿只有自己知道。
隨便提一下其實(shí)不止動(dòng)態(tài)語(yǔ)言具備鴨子類型,有些靜態(tài)語(yǔ)言也能玩這個(gè)騷操作,感興趣下次再介紹。
網(wǎng)站欄目:Python中的面向接口編程
瀏覽地址:http://fisionsoft.com.cn/article/cogechp.html


咨詢
建站咨詢
