“開(kāi)-閉”原則 (Open-Closed principle, OCP)
- 一個(gè)軟件實(shí)體應(yīng)當(dāng)對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉芥被。
Software entities should be open for extension, but closed for modification.
在設(shè)計(jì)一個(gè)模塊的時(shí)候,應(yīng)當(dāng)使這個(gè)模塊可以在不被修改的前提下被擴(kuò)展届腐。
- “可變性的封裝原則”從工程的角度講解了如何實(shí)現(xiàn)“開(kāi)-閉”原則鸵隧。
“可變性的封裝原則”意味著兩點(diǎn):
* 一種可變性不應(yīng)當(dāng)散落在代碼的很多角落里粉臊,而應(yīng)當(dāng)被封裝到一個(gè)對(duì)象里面鹃两。繼承應(yīng)當(dāng)被看做是封裝變化的方法遗座,而不應(yīng)當(dāng)被認(rèn)為是從一般的對(duì)象生成特殊的對(duì)象方法。
* 一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起俊扳。所有的類圖的繼承結(jié)構(gòu)一般不會(huì)超過(guò)兩層途蒋,不然就意味著將兩種不同的可變性混合在一起。
“開(kāi)-閉”原則與其他原則的關(guān)系:
- 里氏代換原則是馋记,任何基類可以出現(xiàn)的地方号坡,子類一定可以出現(xiàn)。
里氏代換原則是對(duì)“開(kāi)-閉”原則的補(bǔ)充梯醒。實(shí)現(xiàn)“開(kāi)-閉”原則的關(guān)鍵步驟就是抽象化筋帖,而基類與子類的繼承關(guān)系就是抽象化的具體體現(xiàn),所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范冤馏。違反里氏代換原則的,也違背“開(kāi)-閉”原則寄啼,反之不一定成立逮光。
- 依賴倒轉(zhuǎn)原則是,要依賴于抽象墩划,不要依賴于實(shí)現(xiàn)涕刚。
“開(kāi)-閉”原則是目標(biāo),依賴倒轉(zhuǎn)原則是手段乙帮。
- 合成/聚合復(fù)用原則是杜漠,要盡量使用合成/聚合,而不是繼承關(guān)系達(dá)到復(fù)用的目的察净。
合成/聚合復(fù)用原則與里氏代換原則相輔相成驾茴,兩者都是實(shí)現(xiàn)“開(kāi)-閉”原則的具體步驟的規(guī)范。
- 迪米特法則是氢卡,一個(gè)軟件實(shí)體應(yīng)當(dāng)與盡可能少的其他實(shí)體發(fā)生相互作用锈至。
一個(gè)遵守迪米特原則設(shè)計(jì)出來(lái)的系統(tǒng)在功能需要擴(kuò)展時(shí),會(huì)相對(duì)更容易地做到對(duì)修改的關(guān)閉译秦。
- 接口隔離原則是峡捡,應(yīng)當(dāng)為客戶端提供盡可能小的單獨(dú)的接口击碗,而不是提供大的總接口。
接口隔離原則與廣義的迪米特法則都是對(duì)一個(gè)軟件實(shí)體與其他的軟件實(shí)體的通信的限制们拙。遵循接口隔離原則稍途,會(huì)使一個(gè)軟件系統(tǒng)在功能擴(kuò)展的過(guò)程當(dāng)中,不會(huì)將修改的壓力傳遞到其他的對(duì)象砚婆。
一個(gè)重構(gòu)方法的討論
“將條件轉(zhuǎn)移語(yǔ)句改寫(xiě)成為多態(tài)性”是一條廣為流傳的代碼重構(gòu)做法械拍。
這一做法本身并不能保證“開(kāi)-閉”原則,應(yīng)當(dāng)以“開(kāi)-閉”原則判斷是否需要改寫(xiě)成多態(tài)射沟。條件轉(zhuǎn)移并不是錯(cuò)誤殊者,如果需要,完全可以選擇使用條件轉(zhuǎn)移验夯。
如果一個(gè)條件轉(zhuǎn)移語(yǔ)句確實(shí)封裝了某種商務(wù)邏輯的可變性猖吴,那么將此種可變性封裝起來(lái)就符合“開(kāi)-閉”原則設(shè)計(jì)思想了。如果一個(gè)條件轉(zhuǎn)移語(yǔ)句沒(méi)有涉及重要的商務(wù)邏輯挥转,或者不會(huì)隨著時(shí)間的變化而變化海蔽,也不意味著任何的可擴(kuò)展性,那么它就沒(méi)有涉及任何有意義的可變性绑谣。這時(shí)候?qū)⑦@個(gè)條件轉(zhuǎn)移語(yǔ)句改寫(xiě)成多態(tài)性就是一種沒(méi)有意義的浪費(fèi)党窜。
- 抽象類應(yīng)當(dāng)擁有盡可能多的共同代碼
在一個(gè)繼承的等級(jí)結(jié)構(gòu)中,共同的代碼應(yīng)當(dāng)盡量向等級(jí)結(jié)構(gòu)的上方移動(dòng)借宵。把重復(fù)的代碼從子類里面移動(dòng)到超類里面幌衣,可以提高代碼的復(fù)用率。在代碼發(fā)生改變時(shí)壤玫,設(shè)計(jì)師只需要修改一個(gè)地方豁护。
- 抽象類應(yīng)當(dāng)擁有盡可能少的數(shù)據(jù)
與代碼的移動(dòng)方向相反,數(shù)據(jù)的移動(dòng)方向是從抽象類到具體類欲间,向等級(jí)結(jié)構(gòu)的下方移動(dòng)楚里。一個(gè)對(duì)象的數(shù)據(jù)不論是否使用都會(huì)占用資源,所以應(yīng)當(dāng)放到等級(jí)結(jié)構(gòu)的低端猎贴。
- 什么時(shí)候才應(yīng)當(dāng)使用繼承復(fù)用
1.子類是超類的一個(gè)特殊種類班缎,而不是超類的一個(gè)角色,Is-A才符合繼承關(guān)系她渴。
2.永遠(yuǎn)不會(huì)出現(xiàn)需要將子類換成另一個(gè)類的子類的情況达址。
3.子類具有擴(kuò)展超類的責(zé)任,而不是具有置換掉(Override)和注銷掉(Nullify)超類的責(zé)任趁耗。
4.只有在分類學(xué)角度上有意義時(shí)苏携,才可以使用繼承,不要從工具類繼承对粪。
里氏代換原則 (Liskov Substitution Principle, LSP)
- 定義嚴(yán)格表達(dá):
如果對(duì)每一個(gè)類型為T(mén)1的對(duì)象O1右冻,都有類型為T(mén)2的對(duì)象O2装蓬,使得以T1定義的所有程序P在所有的對(duì)象O1都代換成O2時(shí),程序P的行為沒(méi)有變化纱扭,那么類型T2是類型T1的子類型牍帚。
簡(jiǎn)單說(shuō),任何基類可以出現(xiàn)的地方乳蛾,子類一定可以出現(xiàn)暗赶。
- 從代碼重構(gòu)的角度理解:
西方著名的思辨,正方形是否是長(zhǎng)方形的子類的問(wèn)題肃叶。
這個(gè)例子意味著里氏代換與通常的數(shù)學(xué)法則和生活常識(shí)有不可混淆的區(qū)別蹂随。應(yīng)當(dāng)盡量從抽象類繼承,而不從具體類繼承因惭。
轉(zhuǎn)自:
“開(kāi)-閉”原則
里氏代換原則