面向?qū)ο髲?fù)習(xí)日志一:抽象類(lèi)與接口

雖然接觸面向?qū)ο笳Z(yǔ)言很長(zhǎng)時(shí)間了,可是要是說(shuō)對(duì)面向?qū)ο蟮乃枷胗卸嗝瓷羁痰牧私?,卻也未必。所以開(kāi)始整理知識(shí),寫(xiě)一點(diǎn)對(duì)面向?qū)ο蟮睦斫庑缘臇|西,算是一種總結(jié)類(lèi)的日志吧。畢竟對(duì)面向?qū)ο蟮闹R(shí)了解的很淺薄,難免有理解有誤的地方,如若您發(fā)現(xiàn),請(qǐng)務(wù)必指出,希望我們共同進(jìn)步。

抽象類(lèi)

首先來(lái)介紹一下抽象類(lèi)是什么??梢院?jiǎn)單的理解:被abstract修飾的方法叫做抽象方法,而一個(gè)類(lèi)如果擁有抽象方法,那么它就是抽象類(lèi),且也必須用abstract修飾。

百度百科中這么說(shuō)抽象類(lèi):

抽象類(lèi)往往用來(lái)表征對(duì)問(wèn)題領(lǐng)域進(jìn)行分析、設(shè)計(jì)中得出的抽象概念,是對(duì)一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象

可以得知抽象類(lèi)是本質(zhì)相同的具體概念的抽象(簡(jiǎn)單點(diǎn),抽象類(lèi)是對(duì)類(lèi)的抽象),抽象是什么,就是不能實(shí)現(xiàn)的,所以抽象類(lèi)不能夠被實(shí)例化。不能實(shí)例化的類(lèi)用來(lái)干什么?答案是作為基類(lèi)使用。

一個(gè)抽象類(lèi)被繼承,由于抽象類(lèi)的特性,我們可以得到任意個(gè)不同的實(shí)現(xiàn)方式,帶來(lái)各種不同的效果,既嚴(yán)謹(jǐn)又靈活。

按照慣例我們列舉一下一個(gè)抽象類(lèi)所具有的特性:

  • 如果一個(gè)類(lèi)中存在一個(gè)及以上方法被聲明為抽象的,那么該類(lèi)必須也是抽象的;反之不正確(一個(gè)類(lèi)是抽象類(lèi),那么該類(lèi)中必然存在一個(gè)及以上方法為抽象方法);
  • 抽象類(lèi)不能被實(shí)例化;
  • 抽象方法必須是抽象的(即不能實(shí)現(xiàn)具體內(nèi)容),并以結(jié)束符結(jié)尾;
  • 抽象類(lèi)允許存在非抽象方法;
  • 繼承抽象類(lèi)的子類(lèi)必須實(shí)現(xiàn)抽象類(lèi)中的抽象方法,除非該子類(lèi)也是抽象類(lèi);
  • 子類(lèi)繼承,實(shí)現(xiàn)的抽象方法不能改變其參數(shù)(數(shù)量/類(lèi)型);
  • 子類(lèi)繼承,其實(shí)現(xiàn)的抽象方法訪問(wèn)控制只能更加寬松,而不能更加嚴(yán)格;
  • 抽象方法訪問(wèn)控制條件不能為private,因?yàn)楸宦暶鳛樗接械姆椒ú荒鼙蛔宇?lèi)繼承。

由上述,你可能模模糊糊知道抽象類(lèi)是用來(lái)做什么的。我再通過(guò)一個(gè)例子來(lái)說(shuō)明:

某日,你老板要求團(tuán)隊(duì)開(kāi)發(fā)一個(gè)數(shù)據(jù)庫(kù)操作類(lèi),必須包括且不限于MySQL,SQLserver,oracle等。老板說(shuō)話了,趕緊弄啊。很快,弄好了,代碼寫(xiě)的也很優(yōu)雅,執(zhí)行效率也不錯(cuò),但是老板很生氣,因?yàn)闆](méi)法用啊,幾個(gè)數(shù)據(jù)庫(kù)類(lèi)中方法完全不一樣,一個(gè)查詢(xún)方法,有定義成select的,有定義成getData的,亂七八糟。

怎么解決這種問(wèn)題。當(dāng)然可以事先溝通好,但是如果使用了抽象類(lèi)就能完全的解決問(wèn)題。定義一個(gè)數(shù)據(jù)庫(kù)抽象類(lèi),在其中定義必要使用的抽象方法,要求各個(gè)數(shù)據(jù)庫(kù)操作類(lèi)必須繼承自該抽象類(lèi),OK,問(wèn)題解決。

如下:

abstract class db {
    # 連接方法
    protected abstract function connect();
    # 執(zhí)行查詢(xún)語(yǔ)句
    public abstract function query($sql);
    # 添加操作
    public abstract function insert($sql);
    # 刪除操作
    public abstract function delete($sql);
    # 更新操作
    public abstract function update($sql);
    # 查詢(xún)操作
    public abstract function select($sql);
}

接口

類(lèi)是對(duì)一組具有共同特征的事物的抽象描述(對(duì)現(xiàn)實(shí)的抽象),而對(duì)不同類(lèi)中本質(zhì)相同的概念的抽象是抽象類(lèi)(類(lèi)的抽象)。如果說(shuō)還存在比抽象類(lèi)更為抽象的,那就是說(shuō) 接口 了。接口是一系列抽象方法的集合。

為什么說(shuō)接口比抽象類(lèi)更加抽象呢。因?yàn)榻涌谥兄荒艽嬖诼暶鳛?code>abstract的公共方法,而不能有普通方法。如下:

interface demo {
    public abstract show();
}

而,這樣是錯(cuò)誤的

interface demo {
    public abstract function show();
    protected abstract function display();
    public function say() {
        echo 'Hello';
    }
}

說(shuō)了不少,到底接口是啥呢?看了一篇文章,上面這么說(shuō)接口:

接口類(lèi)說(shuō)白了,就是一個(gè)類(lèi)的模板,一個(gè)類(lèi)的規(guī)定,如果你屬于這類(lèi),你就必須遵循我的規(guī)定,少一個(gè)都不行,但是具體你怎么去做,我不管,那是你的事

接口類(lèi) 說(shuō)的太不嚴(yán)謹(jǐn)了,應(yīng)該添加引號(hào),需要知道接口并不是類(lèi)。不過(guò)說(shuō)接口是模板比較正確。

而另一篇文章所說(shuō)的我比較認(rèn)同,接口是對(duì)行為的抽象。什么叫行為的抽象?

那先要說(shuō)說(shuō)行為。類(lèi)是對(duì)現(xiàn)實(shí)的抽象嘛,所以用現(xiàn)實(shí)來(lái)舉個(gè)例子。

人的說(shuō)話是不是天生的?自然不是,如果天生會(huì)說(shuō)話,那一般出現(xiàn)在重生小說(shuō)里面。說(shuō)話需要通過(guò)后天學(xué)習(xí),如果不學(xué)習(xí)(例如新聞中被狼收養(yǎng)的孩子)就不會(huì)說(shuō)話(狼孩只會(huì)狼嚎)。在這里,說(shuō)話就是一種行為,是通過(guò)學(xué)習(xí),通過(guò)思想支配表現(xiàn)出來(lái)的??梢哉f(shuō),說(shuō)(人)話就是一個(gè)接口,正常人實(shí)現(xiàn)了該接口,所以能夠說(shuō)話,而狼孩實(shí)現(xiàn)的是狼嚎接口,所以他會(huì)狼嚎,而不會(huì)說(shuō)話。

這個(gè)例子的結(jié)論是,行為是人非天生的(不能直接繼承的),需要通過(guò)后天學(xué)習(xí)(繼承接口)的外在活動(dòng)。

通過(guò)對(duì)行為的抽象,體現(xiàn)在面向?qū)ο笳Z(yǔ)言中,那就是接口,它是不適合在類(lèi)中直接體現(xiàn)(或用來(lái)描述類(lèi))(類(lèi)又可能需要)的方法的集合。

理論結(jié)合實(shí)踐,反應(yīng)在實(shí)際編程中,又如何運(yùn)用接口?慚愧的很,我開(kāi)發(fā)PHP程序可以說(shuō)沒(méi)有運(yùn)用到過(guò)接口。而我見(jiàn)到的運(yùn)用接口的實(shí)例都是通過(guò)多態(tài)來(lái)體現(xiàn)的。

《深入PHP面向?qū)ο蟆⒛J脚c實(shí)踐》書(shū)中所舉的例子,有一個(gè)接口Chargeable,規(guī)定了抽象方法getPrice,被ShopProduct所繼承實(shí)現(xiàn),而CdProduct繼承自ShopProduct。由于實(shí)現(xiàn)接口的類(lèi)繼承接受了它繼承的類(lèi)與所實(shí)現(xiàn)的接口的類(lèi)型,所以CdProduct同時(shí)屬于CdProductShopProduct、Chargeable

所以在客戶(hù)端代碼中可以定義方法cdInfo來(lái)限制僅獲取來(lái)自CdProduct的內(nèi)容:

// ……
public function cdInfo(CdProduct $item) {
    // ……
}

可以定義addProduct來(lái)限制僅允許商品進(jìn)入:

// ……
public function addProduct(ShopProduct $item) {
    // cd、book等商品能夠被添加 而user不能進(jìn)入
    // ……
}

當(dāng)我們只關(guān)注于計(jì)價(jià)的時(shí)候就可以定義定義addChargeable來(lái)確保傳遞的對(duì)象存在計(jì)價(jià)方法:

// ……
public function addChargeable(Chargeable $item) {
    // ……
}

好了,對(duì)抽象類(lèi)與接口本次就寫(xiě)到這里,等過(guò)一段時(shí)間再來(lái)做新的總結(jié),可能會(huì)有新的收獲。由于本人才疏學(xué)淺,理解或解釋不當(dāng)?shù)牡胤?,?qǐng)務(wù)必指出,不勝感激。

參考

java提高篇(四)-----抽象類(lèi)與接口
抽象類(lèi)與接口的區(qū)別

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容