SOLID原則是由五個(gè)設(shè)計(jì)原則組成:單一職責(zé)原則(SRP)嫉沽,開閉原則(OCP),里式替換原則(LSP)俏竞,接口隔離原則(ISP)绸硕,依賴反轉(zhuǎn)原則(DIP)
單一職責(zé)原則(SRP)
概念
單一職責(zé)原則的英文是 Single Responsibility Principle,縮寫為 SRP魂毁。
一個(gè)類只負(fù)責(zé)完成一個(gè)職責(zé)或者功能玻佩。不要設(shè)計(jì)大而全的類,要設(shè)計(jì)粒度小席楚、功能單一的類夺蛇。單一職責(zé)原則是為了實(shí)現(xiàn)代碼高內(nèi)聚、低耦合酣胀,提高代碼的復(fù)用性刁赦、可讀性娶聘、可維護(hù)性。
如何判斷類的職責(zé)是否足夠單一甚脉?
不同的應(yīng)用場景丸升、不同階段的需求背景、不同的業(yè)務(wù)層面牺氨,對同一個(gè)類的職責(zé)是否單一狡耻,可能會有不同的判定結(jié)果。
一些側(cè)面的判斷指標(biāo)更具有指導(dǎo)意義和可執(zhí)行性猴凹,比如夷狰,出現(xiàn)下面這些情況就有可能說明這類的設(shè)計(jì)不滿足單一職責(zé)原則:
類中的代碼行數(shù)、函數(shù)或者屬性過多郊霎;
類依賴的其他類過多沼头,或者依賴類的其他類過多;
私有方法過多书劝;
比較難給類起一個(gè)合適的名字进倍;
類中大量的方法都是集中操作類中的某幾個(gè)屬性。
類的職責(zé)是否設(shè)計(jì)得越單一越好购对?
單一職責(zé)原則是為了實(shí)現(xiàn)代碼高內(nèi)聚猾昆、低耦合,如果拆分得過細(xì)骡苞,實(shí)際上會適得其反垂蜗,反倒會降低內(nèi)聚性,也會影響代碼的可維護(hù)性解幽。
開閉原則(OCP)
概念
開閉原則的英文全稱是 Open Closed Principle贴见,簡寫為 OCP。
軟件實(shí)體(模塊亚铁、類蝇刀、方法等)應(yīng)該“對擴(kuò)展開放、對修改關(guān)閉”徘溢。
添加一個(gè)新的功能吞琐,應(yīng)該是通過在已有代碼基礎(chǔ)上擴(kuò)展代碼(新增模塊、類然爆、方法站粟、屬性等),而非修改已有代碼(修改模塊曾雕、類奴烙、方法、屬性等)的方式來完成。關(guān)于定義切诀,我們有兩點(diǎn)要注意揩环。第一點(diǎn)是,開閉原則并不是說完全杜絕修改幅虑,而是以最小的修改代碼的代價(jià)來完成新功能的開發(fā)丰滑。第二點(diǎn)是,同樣的代碼改動倒庵,在粗代碼粒度下褒墨,可能被認(rèn)定為“修改”;在細(xì)代碼粒度下擎宝,可能又被認(rèn)定為“擴(kuò)展”郁妈。
如何做到“對擴(kuò)展開放、修改關(guān)閉”绍申?
我們要時(shí)刻具備擴(kuò)展意識噩咪、抽象意識、封裝意識失晴,在寫代碼的時(shí)候剧腻,多思考這段代碼未來可能有哪些需求變更拘央,如何設(shè)計(jì)代碼結(jié)構(gòu)涂屁,事先留好擴(kuò)展點(diǎn),以便將新的代碼靈活地插入到擴(kuò)展點(diǎn)上灰伟。
23 種經(jīng)典設(shè)計(jì)模式拆又,大部分都是為了解決代碼的擴(kuò)展性問題而總結(jié)出來的,都是以開閉原則為指導(dǎo)原則的栏账。最常用來提高代碼擴(kuò)展性的方法有:多態(tài)帖族、依賴注入、基于接口而非實(shí)現(xiàn)編程挡爵,以及大部分的設(shè)計(jì)模式(比如竖般,裝飾、策略茶鹃、模板涣雕、職責(zé)鏈、狀態(tài))闭翩。
里式替換原則(LSP)
概念
里式替換原則的英文翻譯是:Liskov Substitution Principle挣郭,縮寫為 LSP。
子類對象能夠替換程序中父類對象出現(xiàn)的任何地方疗韵,并且保證原來程序的邏輯行為不變及正確性不被破壞兑障。
里式替換原則是用來指導(dǎo),繼承關(guān)系中子類該如何設(shè)計(jì)的一個(gè)原則。理解里式替換原則流译,最核心的就是理解“design by contract逞怨,按照協(xié)議來設(shè)計(jì)”這幾個(gè)字。父類定義了函數(shù)的“約定”(或者叫協(xié)議)福澡,那子類可以改變函數(shù)的內(nèi)部實(shí)現(xiàn)邏輯骇钦,但不能改變函數(shù)原有的“約定”。這里的約定包括:函數(shù)聲明要實(shí)現(xiàn)的功能竞漾;對輸入眯搭、輸出、異常的約定业岁;甚至包括注釋中所羅列的任何特殊說明鳞仙。
里式替換原則跟多態(tài)的區(qū)別
雖然從定義描述和代碼實(shí)現(xiàn)上來看,多態(tài)和里式替換有點(diǎn)類似笔时,但它們關(guān)注的角度是不一樣的棍好。多態(tài)是面向?qū)ο缶幊痰囊淮筇匦裕彩敲嫦驅(qū)ο缶幊陶Z言的一種語法允耿。它是一種代碼實(shí)現(xiàn)的思路借笙。而里式替換是一種設(shè)計(jì)原則,用來指導(dǎo)繼承關(guān)系中子類該如何設(shè)計(jì)较锡,子類的設(shè)計(jì)要保證在替換父類的時(shí)候业稼,不改變原有程序的邏輯及不破壞原有程序的正確性。
接口隔離原則(ISP)
概念
接口隔離原則的英文翻譯是“ Interface Segregation Principle”蚂蕴,縮寫為 ISP低散。
客戶端不應(yīng)該強(qiáng)迫依賴它不需要的接口。其中的“客戶端”骡楼,可以理解為接口的調(diào)用者或者使用者熔号。
接口的設(shè)計(jì)要盡量單一,不要讓接口的實(shí)現(xiàn)類和調(diào)用者鸟整,依賴不需要的接口函數(shù)引镊。
接口隔離原則與單一職責(zé)原則的區(qū)別
單一職責(zé)原則針對的是模塊、類篮条、接口的設(shè)計(jì)弟头。接口隔離原則相對于單一職責(zé)原則,一方面更側(cè)重于接口的設(shè)計(jì)兑燥,另一方面它的思考角度也是不同的亮瓷。接口隔離原則提供了一種判斷接口的職責(zé)是否單一的標(biāo)準(zhǔn):通過調(diào)用者如何使用接口來間接地判定。如果調(diào)用者只使用部分接口或接口的部分功能降瞳,那接口的設(shè)計(jì)就不夠職責(zé)單一嘱支。
依賴反轉(zhuǎn)原則(DIP)
概念
依賴反轉(zhuǎn)原則蚓胸。依賴反轉(zhuǎn)原則的英文翻譯是 Dependency Inversion Principle,縮寫為 DIP除师。
高層模塊不要依賴低層模塊沛膳。高層模塊和低層模塊應(yīng)該通過抽象來互相依賴。除此之外汛聚,抽象不要依賴具體實(shí)現(xiàn)細(xì)節(jié)锹安,具體實(shí)現(xiàn)細(xì)節(jié)依賴抽象。
所謂高層模塊和低層模塊的劃分倚舀,簡單來說就是叹哭,在調(diào)用鏈上,調(diào)用者屬于高層痕貌,被調(diào)用者屬于低層风罩。
控制反轉(zhuǎn)(IOC)
這里的“控制”指的是對程序執(zhí)行流程的控制,而“反轉(zhuǎn)”指的是在沒有使用框架之前舵稠,程序員自己控制整個(gè)程序的執(zhí)行超升。在使用框架之后,整個(gè)程序的執(zhí)行流程可以通過框架來控制哺徊。流程的控制權(quán)從程序員“反轉(zhuǎn)”到了框架室琢。
實(shí)現(xiàn)控制反轉(zhuǎn)的方法有很多,控制反轉(zhuǎn)并不是一種具體的實(shí)現(xiàn)技巧落追,而是一個(gè)比較籠統(tǒng)的設(shè)計(jì)思想盈滴,一般用來指導(dǎo)框架層面的設(shè)計(jì)。
依賴注入(DI)
什么是依賴注入呢淋硝?我們用一句話來概括就是:不通過 new() 的方式在類內(nèi)部創(chuàng)建依賴類對象雹熬,而是將依賴的類對象在外部創(chuàng)建好之后宽菜,通過構(gòu)造函數(shù)谣膳、函數(shù)參數(shù)等方式傳遞(或注入)給類使用。
KISS 原則
概念
KISS 原則铅乡。英文是 Keep It Simple and Stupid继谚,縮寫為 KISS。
盡量保持簡單
KISS 原則中的“簡單”并不是以代碼行數(shù)來考量的阵幸。代碼行數(shù)越少并不代表代碼越簡單花履,我們還要考慮邏輯復(fù)雜度、實(shí)現(xiàn)難度挚赊、代碼的可讀性等诡壁。而且,本身就復(fù)雜的問題荠割,用復(fù)雜的方法解決妹卿,并不違背 KISS 原則旺矾。除此之外,同樣的代碼夺克,在某個(gè)業(yè)務(wù)場景下滿足 KISS 原則箕宙,換一個(gè)應(yīng)用場景可能就不滿足了。
對于如何寫出滿足 KISS 原則的代碼
不要使用同事可能不懂的技術(shù)來實(shí)現(xiàn)代碼铺纽;
不要重復(fù)造輪子柬帕,要善于使用已經(jīng)有的工具類庫;
不要過度優(yōu)化狡门。
DRY 原則
概念
DRY 原則為Don’t Repeat Yourself
不要重復(fù)造輪子
實(shí)現(xiàn)邏輯重復(fù)陷寝,但功能語義不重復(fù)的代碼,并不違反 DRY 原則其馏。實(shí)現(xiàn)邏輯不重復(fù)盼铁,但功能語義重復(fù)的代碼,也算是違反 DRY 原則尝偎。除此之外饶火,代碼執(zhí)行重復(fù)也算是違反 DRY 原則。
提高代碼可復(fù)用性的一些方法
減少代碼耦合
滿足單一職責(zé)原則
模塊化
業(yè)務(wù)與非業(yè)務(wù)邏輯分離
通用代碼下沉
繼承致扯、多態(tài)肤寝、抽象、封裝
應(yīng)用模板等設(shè)計(jì)模式
我們在第一次寫代碼的時(shí)候抖僵,如果當(dāng)下沒有復(fù)用的需求鲤看,而未來的復(fù)用需求也不是特別明確,并且開發(fā)可復(fù)用代碼的成本比較高耍群,那我們就不需要考慮代碼的復(fù)用性义桂。在之后開發(fā)新的功能的時(shí)候,發(fā)現(xiàn)可以復(fù)用之前寫的這段代碼蹈垢,那我們就重構(gòu)這段代碼慷吊,讓其變得更加可復(fù)用。
相比于代碼的可復(fù)用性曹抬,DRY 原則適用性更強(qiáng)一些溉瓶。我們可以不寫可復(fù)用的代碼,但一定不能寫重復(fù)的代碼谤民。
迪米特法則(LOD)
概念
迪米特法則的英文翻譯是:Law of Demeter堰酿,縮寫是 LOD。它還有另外一個(gè)更加達(dá)意的英文翻譯為:The Least Knowledge Principle张足。
最小知識原則
每個(gè)模塊只應(yīng)該了解那些與它關(guān)系密切的模塊的有限知識触创。
不該有直接依賴關(guān)系的類之間,不要有依賴为牍。有依賴關(guān)系的類之間哼绑,盡量只依賴必要的接口顺饮。迪米特法則是希望減少類之間的耦合,讓類越獨(dú)立越好凌那。每個(gè)類都應(yīng)該少了解系統(tǒng)的其他部分兼雄。一旦發(fā)生變化,需要了解這一變化的類就會比較少帽蝶。
如何理解“高內(nèi)聚赦肋、松耦合”?
所謂高內(nèi)聚励稳,就是指相近的功能應(yīng)該放到同一個(gè)類中佃乘,不相近的功能不要放到同一類中。相近的功能往往會被同時(shí)修改驹尼,放到同一個(gè)類中趣避,修改會比較集中。
所謂松耦合指的是新翎,在代碼中程帕,類與類之間的依賴關(guān)系簡單清晰。即使兩個(gè)類有依賴關(guān)系地啰,一個(gè)類的代碼改動也不會或者很少導(dǎo)致依賴類的代碼改動愁拭。