參考牢記面向?qū)ο笪鍌€(gè)基本原則;深入理解Java中的重寫(xiě)和重載;
Java中方法的重寫(xiě)與成員變量的隱藏;深入理解Java中的組合和繼承
有一些個(gè)人看法,如有錯(cuò)誤歡迎指正
一、三大基本特征
Java是一個(gè)面向?qū)ο蟮恼Z(yǔ)言。封裝、繼承、多態(tài)是面向?qū)ο蟮娜齻€(gè)特征。
封裝
意義在于保護(hù)和隱藏。隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)訪(fǎng)問(wèn)方法,且控制訪(fǎng)問(wèn)級(jí)別。Java用類(lèi)實(shí)現(xiàn)封裝,用封裝實(shí)現(xiàn)高內(nèi)聚(內(nèi)部關(guān)聯(lián))和低耦合(外部關(guān)聯(lián))
繼承
意義在于復(fù)用。Java的復(fù)用技術(shù)有繼承、組合、代理,三種表現(xiàn)形式。
子類(lèi)繼承父類(lèi),是is-a關(guān)系,并且父類(lèi)是已知的類(lèi),編譯時(shí)就確定了。破壞了封裝性,子類(lèi)知道父類(lèi)的細(xì)節(jié),并且可以隨意調(diào)用(除private)。但不是父類(lèi)的什么都可以繼承和重寫(xiě),父類(lèi)的靜態(tài)域只能被繼承,不能被重寫(xiě),而是被隱藏,即調(diào)用的只能是父類(lèi)的屬性和方法。所以子類(lèi)與父類(lèi)的耦合性會(huì)非常高。由于子類(lèi)可以直接使用父類(lèi)實(shí)現(xiàn)的方法,對(duì)子類(lèi)來(lái)說(shuō),一旦從父類(lèi)那里繼承卻沒(méi)有Override的部分改變了,子類(lèi)也必須做相應(yīng)改變。
組合,是一種拼裝,擁有has-a關(guān)系。即A類(lèi)內(nèi)有聲明為B的成員。B可以是接口,所以在編譯時(shí),還不知道具體要用到哪個(gè)類(lèi)。并且調(diào)用都是用B.方法名調(diào)用的,實(shí)現(xiàn)細(xì)節(jié)由B決定,運(yùn)行時(shí)才知道具體執(zhí)行的類(lèi),且改變也不會(huì)影響A,因?yàn)锳只知道傳入?yún)?shù)和預(yù)期結(jié)果,并不關(guān)心細(xì)節(jié)。
雖然組合看起來(lái)更優(yōu)秀,在都可以使用時(shí),推薦用組合解耦合。但是有些情況(需要重寫(xiě)的時(shí)候)還是更加適合用繼承:
繼承要慎用,其使用場(chǎng)合僅限于你確信使用該技術(shù)有效的情況。一個(gè)判斷方法是,問(wèn)一問(wèn)自己是否需要從新類(lèi)向基類(lèi)進(jìn)行向上轉(zhuǎn)型。如果是必須的,則繼承是必要的。反之則應(yīng)該好好考慮是否需要繼承?!?a target="_blank" rel="nofollow">Java編程思想》
只有當(dāng)子類(lèi)真正是超類(lèi)的子類(lèi)型時(shí),才適合用繼承。換句話(huà)說(shuō),對(duì)于兩個(gè)類(lèi)A和B,只有當(dāng)兩者之間確實(shí)存在
is-a關(guān)系的時(shí)候,類(lèi)B才應(yīng)該繼續(xù)類(lèi)A。《Effective Java》
多態(tài)
目的也是為了解耦合。指允許不同類(lèi)的對(duì)象對(duì)同一消息做出響應(yīng)。同一個(gè)函數(shù)調(diào)用,可以自動(dòng)采用不同的行為方式。
? 分為編譯時(shí)多態(tài)(參數(shù)數(shù)量不同)和運(yùn)行時(shí)多態(tài)(運(yùn)行時(shí)實(shí)際調(diào)用者不同)。還有一種說(shuō)法是,編譯時(shí)已經(jīng)確定的重載,不能算作一種多態(tài)的方式。那按這種說(shuō)法就只有運(yùn)行時(shí)多態(tài)一種稱(chēng)為多態(tài)。
? 編譯時(shí)多態(tài)是方法的重載(Overload),在編譯時(shí)根據(jù)參數(shù)列表選擇方法名一致的方法中,用哪一個(gè)(JVM方法簽名=方法名+參數(shù)列表)。
? 運(yùn)行時(shí)多態(tài)是重寫(xiě)(Override)運(yùn)用的技術(shù)叫動(dòng)態(tài)綁定(dynamic binding)即調(diào)用者聲明為接口或父類(lèi)(可以是普通的類(lèi)也可以是抽象類(lèi)),只有執(zhí)行到這里才知道具體調(diào)用的是哪個(gè)類(lèi)實(shí)現(xiàn)的那個(gè)方法。方法簽名完全一致,所以會(huì)覆蓋掉父類(lèi)的實(shí)現(xiàn),即自動(dòng)向上轉(zhuǎn)型。
二、五大基本原則
五大基本原則分別是:單一職責(zé)(同一件事用同一個(gè)類(lèi),用參數(shù)來(lái)區(qū)分細(xì)節(jié))、開(kāi)放封閉(一旦開(kāi)發(fā)好一個(gè)功能即能獨(dú)立運(yùn)轉(zhuǎn),新的功能隨時(shí)能追加,但與之無(wú)關(guān))、Liskov替換(動(dòng)態(tài)綁定不影響調(diào)用者功能)、依賴(lài)倒置(接口和實(shí)現(xiàn)分離,調(diào)用者聲明只用接口)、接口隔離(避免胖接口,JDK8的Defult就在緩解胖接口問(wèn)題)
單一職責(zé)原則(Single-Resposibility Principle)
其核心思想為:一個(gè)類(lèi),最好只做一件事,只有一個(gè)引起它的變化。單一職責(zé)原則可以看做是低耦合、高內(nèi)聚在面向?qū)ο笤瓌t上的引申。通常意義下的單一職責(zé),就是指只有一種單一功能,不要為類(lèi)實(shí)現(xiàn)過(guò)多的功能點(diǎn),以保證實(shí)體只有一個(gè)引起它變化的原因。
開(kāi)放封閉原則(Open-Closed principle)
開(kāi)放封閉原則主要體現(xiàn)在兩個(gè)方面
對(duì)擴(kuò)展開(kāi)放,意味著有新的需求或變化時(shí),可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展,以適應(yīng)新的情況。
對(duì)修改封閉,意味著類(lèi)一旦設(shè)計(jì)完成,就可以獨(dú)立完成其工作,而不要對(duì)其進(jìn)行任何嘗試的修改。
Liskov替換原則(Liskov-Substituion Principle)
其核心思想是:子類(lèi)必須能夠替換其基類(lèi)。這一思想體現(xiàn)為對(duì)繼承機(jī)制的約束規(guī)范,將基類(lèi)替換為子類(lèi),程序的行為不會(huì)發(fā)生任何變化。同時(shí),這一約束反過(guò)來(lái)則是不成立的,子類(lèi)可以替換基類(lèi),但是基類(lèi)不一定能替換子類(lèi)。 ? 實(shí)現(xiàn)的方法是面向接口編程:將公共部分抽象為基類(lèi)接口或抽象類(lèi),通過(guò)Extract Abstract Class,在子類(lèi)中通過(guò)覆寫(xiě)父類(lèi)的方法實(shí)現(xiàn)新的方式支持同樣的職責(zé)。 ? Liskov替換原則能夠保證系統(tǒng)具有良好的拓展性,同時(shí)實(shí)現(xiàn)基于多態(tài)的抽象機(jī)制,能夠減少代碼冗余,避免運(yùn)行期的類(lèi)型判別。
依賴(lài)倒置原則(Dependecy-Inversion Principle)
其核心思想是:高層模塊不依賴(lài)于底層模塊,二者都同依賴(lài)于抽象; ? 我們知道,依賴(lài)一定會(huì)存在于類(lèi)與類(lèi)、模塊與模塊之間。當(dāng)兩個(gè)模塊之間存在緊密的耦合關(guān)系時(shí),最好的方法就是分離接口和實(shí)現(xiàn):在依賴(lài)之間定義一個(gè)抽象的接口使得高層模塊調(diào)用接口,而底層模塊實(shí)現(xiàn)接口的定義,以此來(lái)有效控制耦合關(guān)系,達(dá)到依賴(lài)于抽象的設(shè)計(jì)目標(biāo)。
接口隔離原則(Interface-Segregation Principle)
其核心思想是:使用多個(gè)小的專(zhuān)門(mén)的接口,而不要使用一個(gè)大的總接口。 具體而言,接口隔離原則體現(xiàn)在:接口應(yīng)該是內(nèi)聚的,應(yīng)該避免“胖”接口。一個(gè)類(lèi)對(duì)另外一個(gè)類(lèi)的依賴(lài)應(yīng)該建立在最小的接口上,不要強(qiáng)迫依賴(lài)不用的方法,這是一種接口污染。 ? 接口有效地將細(xì)節(jié)和抽象隔離,體現(xiàn)了對(duì)抽象編程的一切好處,接口隔離強(qiáng)調(diào)接口的單一性。而胖接口存在明顯的弊端,會(huì)導(dǎo)致實(shí)現(xiàn)的類(lèi)型必須完全實(shí)現(xiàn)接口的所有方法、屬性等;
分離的手段主要有以下兩種:
委托分離,通過(guò)增加一個(gè)新的類(lèi)型來(lái)委托客戶(hù)的請(qǐng)求,隔離客戶(hù)和接口的直接依賴(lài),但是會(huì)增加系統(tǒng)的開(kāi)銷(xiāo)。
多重繼承分離,通過(guò)接口多繼承來(lái)實(shí)現(xiàn)客戶(hù)的需求,這種方式是較好
JDK8允許接口有默認(rèn)實(shí)現(xiàn),defult方法。它的出現(xiàn)可以緩解胖接口問(wèn)題。聲明為defult的方法后,方法可以有花括號(hào),里面可以有默認(rèn)實(shí)現(xiàn)。default方法子類(lèi)可以重寫(xiě)也可以不重寫(xiě)。
謝謝觀看,如果有用麻煩點(diǎn)個(gè)喜歡,對(duì)我是莫大的鼓勵(lì)。