自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python 中的面向接口編程

開發(fā) 后端
”面向接口編程“寫 Java 的朋友耳朵已經(jīng)可以聽出干繭了吧,當然這個思想在 Java 中非常重要,甚至幾乎所有的編程語言都需要,畢竟程序具有良好的擴展性、維護性誰都不能拒絕。

[[375774]]

本文轉(zhuǎn)載自微信公眾號「 crossoverJie」,作者 crossoverJie。轉(zhuǎn)載本文請聯(lián)系 crossoverJie公眾號。

前言

”面向接口編程“寫 Java 的朋友耳朵已經(jīng)可以聽出干繭了吧,當然這個思想在 Java 中非常重要,甚至幾乎所有的編程語言都需要,畢竟程序具有良好的擴展性、維護性誰都不能拒絕。

最近無意間看到了我剛開始寫 Python 時的部分代碼,當時實現(xiàn)的需求有個很明顯的特點:

  • 不同對象具有公共的行為能力,但具體每個對象的實現(xiàn)方式又各不相同。

說人話就是商戶需要接入平臺,接入的步驟相同,但具體實現(xiàn)不同。

作為一個”資深“ Javaer,需求還沒看完我就洋洋灑灑的把各個實現(xiàn)類寫好了:

當然最終也順利實現(xiàn)需求,甚至把組里一個沒寫過 Java 的大哥唬的一愣一愣的,直呼牛逼。

不過事后也給我吐槽:

  • 你這設計是不錯,但是感覺好復雜,跟代碼時要找到真正的業(yè)務邏輯(實現(xiàn)類)得繞幾圈。

截止目前 Python 寫多了,我總算是能總結(jié)他的感受:就是不夠 Pythonic。

雖說 Python 沒有類似 Java 這樣的 Interface 特性,但作為面向?qū)ο蟮母呒壵Z言也是支持繼承的;

在這里我們也可以利用繼承的特性來實現(xiàn)面向接口編程:

  1. class Car: 
  2.     def run(self): 
  3.         pass 
  4.  
  5. class Benz(Car): 
  6.     def run(self): 
  7.         print("benz run"
  8.  
  9. class BMW(Car): 
  10.  
  11.     def run(self): 
  12.         print("bwm run"
  13.  
  14. def run(car): 
  15.     car.run() 
  16.  
  17. if __name__ == "__main__"
  18.     benz = Benz() 
  19.     bmw = BMW() 
  20.  
  21.     run(benz) 
  22.     run(bmw) 

代碼非常簡單,在 Python 中也沒有類似于 Java 中的 extends 關(guān)鍵字,只需要在類聲明末尾用括號包含基類即可。

這樣在每個子類中就能單獨實現(xiàn)業(yè)務邏輯,方便擴展和維護。

類型檢查

由于 Python 作為一個動態(tài)類型語言,無法做到 Java 那樣在編譯期間校驗一個類是否完全實現(xiàn)了某個接口的所有方法。

為此 Python 提供了解決辦法,那就是 abc(Abstract Base Classes) ,當我們將基類用 abc 聲明時就能近似做到:

  1. import abc 
  2. class Car(abc.ABC): 
  3.     @abc.abstractmethod 
  4.     def run(self): 
  5.         pass 
  6.  
  7. class Benz(Car): 
  8.     def run(self): 
  9.         print("benz run"
  10.  
  11. class BMW(Car): 
  12.     pass 
  13.  
  14. def run(car): 
  15.     car.run() 
  16.  
  17. if __name__ == "__main__"
  18.     benz = Benz() 
  19.     bmw = BMW() 
  20.  
  21.     run(benz) 
  22.     run(bmw) 

一旦有類沒有實現(xiàn)方法時,運行期間便會拋出異常:

  1. bmw = BMW() 
  2. TypeError: Can't instantiate abstract class BMW with abstract methods run 

雖然無法做到在運行之前(畢竟不需要編譯)進行校驗,但有總比沒有好。

鴨子類型

以上兩種方式看似已經(jīng)畢竟優(yōu)雅的實現(xiàn)面向接口編程了,但實際上也不夠 Pythonic。

在繼續(xù)之前我們先聊聊接口的本質(zhì)到底是什么?

在 Java 這類靜態(tài)語言中面向接口編程是比較麻煩的,也就是我們常說的子類向父類轉(zhuǎn)型,因此需要編寫額外的代碼。

帶來的好處也是顯而易見,只需要父類便可運行。

但我們也不必過于執(zhí)著于接口,它本身只是一個協(xié)議、規(guī)范,并不特指 Java 中的 Interface,甚至有些語言壓根沒有這個關(guān)鍵字。

動態(tài)語言的特性也不需要強制校驗是否實現(xiàn)了方法。

在 Python 中我們可以利用鴨子類型來優(yōu)雅的實現(xiàn)面向接口編程。

在這之前先了解下鴨子類型,借用維基百科的說法:

  • “當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。”

我用大白話翻譯下就是:

即便兩個完全不想干的類,如果他們都實現(xiàn)了相同的方法,那就可以把他們當做同一類型的類來使用。

舉個簡單例子:

  1. class Order
  2.     def create(self): 
  3.         pass 
  4.  
  5. class User
  6.     def create(self): 
  7.         pass 
  8.  
  9. def create(obj): 
  10.     obj.create() 
  11.  
  12. if __name__ == "__main__"
  13.     order = Order() 
  14.     user = User() 
  15.     create(order
  16.     create(user

這里的 order 和 user 本身完全沒有關(guān)系,只是他們都有相同方法,又得益于動態(tài)語言沒法校驗類型的特點,所以完全可以在運行的時候認為他們是同一種類型。

因此基于鴨子類型,之前的代碼我們可以稍作簡化:

  1. class Car: 
  2.     def run(self): 
  3.         pass 
  4.  
  5. class Benz: 
  6.     def run(self): 
  7.         print("benz run"
  8.  
  9. class BMW: 
  10.     def run(self): 
  11.         print("bwm run"
  12.  
  13. def run(car): 
  14.     car.run() 
  15.  
  16. if __name__ == "__main__"
  17.     benz = Benz() 
  18.     bmw = BMW() 
  19.  
  20.     run(benz) 
  21.     run(bmw) 

因為在鴨子類型中我們在意的是它的行為,而不是他們的類型;所以完全可以不用繼承便可以實現(xiàn)面向接口編程。

總結(jié)

我覺得平時沒有接觸過動態(tài)類型語言的朋友,在了解完這些之后會發(fā)現(xiàn)新大陸,就像是 Python 老手第一次使用 Java 時;雖然覺得語法啰嗦,但也會羨慕它的類型檢查、參數(shù)驗證這類特點。

動靜語言之爭這里不做討論了,各有各的好,鞋好不好穿只有自己知道。

隨便提一下其實不止動態(tài)語言具備鴨子類型,有些靜態(tài)語言也能玩這個騷操作,感興趣下次再介紹。

 

責任編輯:武曉燕 來源: crossoverJie
相關(guān)推薦

2013-07-30 09:42:41

實現(xiàn)編程接口編程對象編程

2009-07-02 13:25:00

消除實現(xiàn)繼承面向接口編程Java

2020-07-23 17:29:47

接口編程代碼

2023-04-19 08:43:52

Python面向?qū)ο缶幊?/a>

2023-10-04 17:25:01

面向接口編程

2023-10-13 07:36:58

Java函數(shù)式編程

2010-01-20 09:48:44

面向?qū)ο?/a>

2010-02-26 14:40:15

Python應用程序

2019-03-26 10:50:22

Python面向?qū)ο?/a>編程語言

2023-01-10 09:06:17

2023-12-11 15:32:30

面向?qū)ο缶幊?/a>OOPpython

2009-01-16 08:52:26

面向?qū)ο?/a>OOP編程

2010-07-20 09:13:55

Perl面向?qū)ο缶幊?/a>

2011-07-21 17:19:47

java面向?qū)ο?/a>

2014-05-08 14:13:00

Java面向GC

2023-04-26 00:15:32

python面向?qū)ο?/a>java

2009-06-16 15:02:18

面向?qū)ο缶幊?/a>PHP異常PHP代理

2010-07-20 13:44:02

Perl方法

2022-07-30 23:41:53

面向過程面向?qū)ο?/a>面向協(xié)議編程

2010-11-17 11:31:22

Scala基礎(chǔ)面向?qū)ο?/a>Scala
點贊
收藏

51CTO技術(shù)棧公眾號