day24-抽象類與接口類

接口類

一、繼承有兩種用途:
一:繼承基類的方法,而且作出本身的改變或者擴展(代碼重用)
二:聲明某個子類兼容於某基類,定義一個接口類,接口類中定義了一些接口名(就是函數名)且並未實現接口的功能,子類繼承接口類,而且實現接口中的功能java

二、例子:python

第一步:每定義一種支付類,就經過實例化對象調用相應的支付方法,這樣雖然也能夠實現QQ支付和支付寶支付,但代碼風格不統一
class QQPay():
    def pay(self, money):
        print('QQ支付了%s元' %money)
        
class AliPay():
    def pay(self, money):
        print('支付寶支持了%s元' %money)
qq1 = QQPay()
ali1 = AliPay()
qq1.pay(100)
ali1.pay(200)

結果:
QQ支付了100元
支付寶支持了200元

第二步:定義一個統一支付的函數,經過將實例化對象做爲參數傳遞給這個函數,由函數來執行實例化對象的pay方法
class QQPay():
    def pay(self, money):
        print('QQ支付了%s元' %money)
        
class AliPay():
    def pay(self, money):
        print('支付寶支持了%s元' %money)

def pay(obj, money):
    obj.pay(money)

qq1 = QQPay()
ali1 = AliPay()

pay(qq1, 100)
pay(ali1, 200)
結果:
QQ支付了100元
支付寶支持了200元

第三步:若是代碼後期須要增長新的支付方式,而這時開發人員已經更換,新的開發人員並無依照原來的代碼風格進行統一編寫,雖然也能夠執行,但又破壞了代碼統一性
class WechatPay(payment):
    def fuqian(self, money):
        print('微信支付了%s元' %money)

wechat1 = WechatPay()
結果:微信支付了300元

第四步:咱們先定義一個父類,什麼都不寫,只是要求繼承個人全部類有一個pay方法,這樣就制定了一個規範,這就叫作接口類,或者抽象類.
class payment:
    def pay(self):
        pass

class QQPay(payment):
    def pay(self, money):
        print('QQ支持了%s元' %money)
        
class AliPay(payment):
    def pay(self, money):
        print('支付寶支持了%s元' %money)
        
class WechatPay(payment):
    def pay(self, money):
        print('微信支付了%s元' %money)

def pay(obj, money):
    obj.pay(money)

qq1 = QQPay()
ali1 = AliPay()
wechat1 = WechatPay()

pay(qq1, 100)
pay(ali1, 200)
pay(ali2, 300)

結果:
QQ支持了100元
支付寶支持了200元
微信支付了300元

可是這樣若是新增的方法WechatPay仍然沒有遵循父類中的格式,仍是寫成了下面這樣也仍是能夠執行的
class WechatPay(payment):
    def fuqian(self, money):
        print('微信支付了%s元' %money)
wechat1 = WechatPay()
wechat1.fuqian(300)

第五步:那麼如何強制讓新增的類遵循統一格式呢,須要使用@abstractmethod方法
from abc import ABCMeta, abstractmethod

class payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self):
        pass

class QQPay(payment):
    def pay(self, money):
        print('QQ支持了%s元' %money)
        
class AliPay(payment):
    def pay(self, money):
        print('支付寶支持了%s元' %money)
        
class WechatPay(payment):
    def fuqian(self, money):
        print('微信支付了%s元' %money)

def pay(obj, money):
    obj.pay(money)

qq1 = QQPay()
ali1 = AliPay()
wechat1 = WechatPay()

pay(qq1, 100)
pay(ali1, 200)
wechat1.fuqian(300)
這時若是WechatPay裏面方法名稱不是pay,那麼結果會報錯,TypeError: Can't instantiate abstract class WechatPay with abstract methods pay
因此這時就必需要求WechatPay裏面存在pay方法,程序才能正確執行,這樣就可使用統一的pay函數進行統一調用對象,
代碼修改以下:
class WechatPay(payment):
    def pay(self, money):
        print('微信支付了%s元' %money)

qq1 = QQPay()
ali1 = AliPay()
wechat1 = WechatPay()

pay(qq1, 100)
pay(ali1, 200)
pay(wechat1, 300)

備註:經測試,其實子類中只要有父類中的方法pay便可,即便寫成下面這樣也仍是能夠執行。。。
class WechatPay(payment):
    def fuqian(self, money):
        print('微信支付了%s元' %money)
    def pay(self):
        pass

wechat1 = WechatPay()
wechat1.fuqian(300)


也能夠將對象放在一個字典中進行循環調用
def pay(obj, money):
    obj.pay(money)

qq1 = QQPay()
ali1 = AliPay()
wechat1 = WechatPay()

pay_dict = {qq1: 100, ali1: 200, wechat1: 300}
for i in pay_dict:
    pay(i, pay_dict[i])

QQ支持了100元
支付寶支持了200元
微信支付了300元
View Code

 

實踐中,繼承的第一種含義意義並不很大,甚至經常是有害的。由於它使得子類與基類出現強耦合。git

繼承的第二種含義很是重要。它又叫「接口繼承」。github

接口繼承實質上是要求「作出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無需關心具體細節,可一視同仁的處理實現了特定接口的全部對象」——這在程序設計上,叫作歸一化。編程

歸一化使得高層的外部使用者能夠不加區分的處理全部接口兼容的對象集合設計模式

依賴倒置原則:
1)高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;微信

2)抽象不該該依賴細節,細節應該依賴抽象。換言之,要針對接口編程,而不是針對實現編程ide

在python中根本就沒有一個叫作interface的關鍵字,上面的代碼只是看起來像接口,其實並無起到接口的做用,子類徹底能夠不用去實現接口 ,若是非要去模仿接口的概念,能夠藉助第三方模塊:
http://pypi.python.org/pypi/zope.interface
twisted的twisted\internet\interface.py裏使用zope.interface
文檔https://zopeinterface.readthedocs.io/en/latest/
設計模式:https://github.com/faif/python-patterns函數

接口提取了一羣類共同的函數,能夠把接口當作一個函數的集合,而後讓子類去實現接口中的函數。
這麼作的意義在於歸一化,就是隻要是基於同一個接口實現的類,那麼全部的這些類產生的對象在使用時,用法都同樣。測試

歸一化,讓使用者無需關心對象的類是什麼,只須要知道這些對象都具有某些功能就能夠了,這極大地下降了使用者的使用難度。

好比:咱們定義一個動物接口,接口裏定義了有跑、吃、呼吸等接口函數,這樣老鼠的類去實現了該接口,松鼠的類也去實現了該接口,由兩者分別產生一隻老鼠和一隻松鼠送到你面前,即使是你分別不出哪隻是什麼鼠你確定知道他倆都會跑,都會吃,都能呼吸。

再好比:咱們有一個汽車接口,裏面定義了汽車全部的功能,而後由本田汽車的類,奧迪汽車的類,大衆汽車的類,他們都實現了汽車接口,這樣就好辦了,你們只須要學會了怎麼開汽車,那麼不管是本田,仍是奧迪,仍是大衆咱們都會開了,開的時候根本無需關心我開的是哪一類車,操做手法(函數調用)都同樣

抽象類

一、什麼是抽象類
與java同樣,python也有抽象類的概念可是一樣須要藉助模塊實現,抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化

二、爲何要有抽象類
若是說類是從一堆對象中抽取相同的內容而來的,那麼抽象類就是從一堆類中抽取相同的內容而來的,內容包括數據屬性和函數屬性。
好比咱們有香蕉的類,有蘋果的類,有桃子的類,從這些類抽取相同的內容就是水果這個抽象的類,你吃水果時,要麼是吃一個具體的香蕉,要麼是吃一個具體的桃子。。。。。。你永遠沒法吃到一個叫作水果的東西。

從設計角度去看,若是類是從現實對象抽象而來的,那麼抽象類就是基於類抽象而來的。
從實現角度來看,抽象類與普通類的不一樣之處在於:抽象類中有抽象方法,該類不能被實例化,只能被繼承,且子類必須實現抽象方法。這一點與接口有點相似,但實際上是不一樣的

三、抽象類與接口類抽象類的本質仍是類,指的是一組類的類似性,包括數據屬性(如all_type)和函數屬性(如read、write),而接口只強調函數屬性的類似性。抽象類是一個介於類和接口之間的一個概念,同時具有類和接口的部分特性,能夠用來實現歸一化設計 在python中,並無接口類這種東西,即使不經過專門的模塊定義接口,咱們也應該有一些基本的概念。

相關文章
相關標籤/搜索