對于單一職責(zé)原則,如何判定某個類的職責(zé)是否夠“單一”拍冠?
如何理解單一職責(zé)原則(SRP)?
一個類只負責(zé)完成一個職責(zé)或者功能簇抵。
也就是說庆杜,不要設(shè)計大而全的類,要設(shè)計粒度小碟摆、功能單一的類晃财。換個角度來講就是,一個類包含了兩個或者兩個以上業(yè)務(wù)不相干的功能典蜕,那我們就說它職責(zé)不夠單一断盛,應(yīng)該將它拆分成多個功能更加單一、粒度更細的類愉舔。
如何判斷類的職責(zé)是否足夠單一钢猛?
- 類中的代碼行數(shù)、函數(shù)或者屬性過多轩缤;
- 類依賴的其他類過多命迈,或者依賴類的其他類過多;
- 私有方法過多火的;
- 比較難給類起一個合適的名字壶愤;
- 類中大量的方法都是集中操作類中的某幾個屬性。
類的職責(zé)是否設(shè)計得越單一越好馏鹤?
單一職責(zé)原則通過避免設(shè)計大而全的類征椒,避免將不相關(guān)的功能耦合在一起,來提高類的內(nèi)聚性湃累。同時勃救,類職責(zé)單一碍讨,類依賴的和被依賴的其他類也會變少,減少了代碼的耦合性剪芥,以此來實現(xiàn)代碼的高內(nèi)聚垄开、低耦合琴许。但是税肪,如果拆分得過細,實際上會適得其反榜田,反倒會降低內(nèi)聚性益兄,也會影響代碼的可維護性。
如何做到“對擴展開放箭券、修改關(guān)閉”净捅?擴展和修改各指什么?
如何理解“對擴展開放辩块、修改關(guān)閉”蛔六?
添加一個新的功能應(yīng)該是,在已有代碼基礎(chǔ)上擴展代碼(新增模塊废亭、類国章、方法等),而非修改已有代碼(修改模塊豆村、類液兽、方法等)。
關(guān)于定義掌动,我們有兩點要注意四啰。第一點是,開閉原則并不是說完全杜絕修改粗恢,而是以最小的修改代碼的代價來完成新功能的開發(fā)柑晒。第二點是,同樣的代碼改動眷射,在粗代碼粒度下匙赞,可能被認定為“修改”;在細代碼粒度下凭迹,可能又被認定為“擴展”罚屋。
如何做到“對擴展開放、修改關(guān)閉”嗅绸?
我們要時刻具備擴展意識脾猛、抽象意識、封裝意識鱼鸠。在寫代碼的時候猛拴,我們要多花點時間思考一下羹铅,這段代碼未來可能有哪些需求變更,如何設(shè)計代碼結(jié)構(gòu)愉昆,事先留好擴展點职员,以便在未來需求變更的時候,在不改動代碼整體結(jié)構(gòu)跛溉、做到最小代碼改動的情況下焊切,將新的代碼靈活地插入到擴展點上。
很多設(shè)計原則芳室、設(shè)計思想专肪、設(shè)計模式,都是以提高代碼的擴展性為最終目的的堪侯。特別是 23 種經(jīng)典設(shè)計模式嚎尤,大部分都是為了解決代碼的擴展性問題而總結(jié)出來的,都是以開閉原則為指導(dǎo)原則的伍宦。最常用來提高代碼擴展性的方法有:多態(tài)芽死、依賴注入、基于接口而非實現(xiàn)編程次洼,以及大部分的設(shè)計模式(比如关贵,裝飾、策略滓玖、模板坪哄、職責(zé)鏈、狀態(tài))势篡。
里式替換(LSP)跟多態(tài)有何區(qū)別翩肌?哪些代碼違背了LSP?
如何理解“里式替換原則”禁悠?
子類對象(object of subtype/derived class)能夠替換程序(program)中父類對象(object of base/parent class)出現(xiàn)的任何地方念祭,并且保證原來程序的邏輯行為(behavior)不變及正確性不被破壞。
哪些代碼明顯違背了LSP碍侦?
- 子類違背父類聲明要實現(xiàn)的功能
- 子類違背父類對輸入粱坤、輸出、異常的約定
- 子類違背父類注釋中所羅列的任何特殊說明
接口隔離原則有哪三種應(yīng)用瓷产?原則中的“接口”該如何理解站玄?
如何理解“接口隔離原則”?
接口的調(diào)用者或者使用者不應(yīng)該被強迫依賴它不需要的接口濒旦。
如果把“接口”理解為一組接口集合株旷,可以是某個微服務(wù)的接口,也可以是某個類庫的接口等。如果部分接口只被部分調(diào)用者使用晾剖,我們就需要將這部分接口隔離出來锉矢,單獨給這部分調(diào)用者使用,而不強迫其他調(diào)用者也依賴這部分不會被用到的接口齿尽。
如果把“接口”理解為單個 API 接口或函數(shù)沽损,部分調(diào)用者只需要函數(shù)中的部分功能,那我們就需要把函數(shù)拆分成粒度更細的多個函數(shù)循头,讓調(diào)用者只依賴它需要的那個細粒度函數(shù)绵估。
如果把“接口”理解為 OOP 中的接口,也可以理解為面向?qū)ο缶幊陶Z言中的接口語法贷岸。那接口的設(shè)計要盡量單一壹士,不要讓接口的實現(xiàn)類和調(diào)用者磷雇,依賴不需要的接口函數(shù)偿警。
接口隔離原則與單一職責(zé)原則的區(qū)別
單一職責(zé)原則針對的是模塊、類唯笙、接口的設(shè)計螟蒸。接口隔離原則相對于單一職責(zé)原則,一方面更側(cè)重于接口的設(shè)計崩掘,另一方面它的思考角度也是不同的七嫌。接口隔離原則提供了一種判斷接口的職責(zé)是否單一的標準:通過調(diào)用者如何使用接口來間接地判定。如果調(diào)用者只使用部分接口或接口的部分功能苞慢,那接口的設(shè)計就不夠職責(zé)單一诵原。
控制反轉(zhuǎn)、依賴反轉(zhuǎn)挽放、依賴注入绍赛,這三者有何區(qū)別和聯(lián)系?
控制反轉(zhuǎn)(IOC)
“控制”指的是對程序執(zhí)行流程的控制辑畦,“反轉(zhuǎn)”指的是在沒有使用框架之前吗蚌,程序員自己控制整個程序的執(zhí)行。在使用框架之后纯出,整個程序的執(zhí)行流程可以通過框架來控制蚯妇。流程的控制權(quán)從程序員“反轉(zhuǎn)”到了框架。
依賴注入(DI)
不通過 new() 的方式在類內(nèi)部創(chuàng)建依賴類對象暂筝,而是將依賴的類對象在外部創(chuàng)建好之后箩言,通過構(gòu)造函數(shù)、函數(shù)參數(shù)等方式傳遞(或注入)給類使用焕襟。
依賴注入框架(DI Framework)
通過依賴注入框架提供的擴展點陨收,簡單配置一下所有需要的類及其類與類之間依賴關(guān)系,就可以實現(xiàn)由框架來自動創(chuàng)建對象胧洒、管理對象的生命周期畏吓、依賴注入等原本需要程序員來做的事情墨状。
依賴反轉(zhuǎn)原則(DIP)
依賴反轉(zhuǎn)原則也叫作依賴倒置原則。這條原則跟控制反轉(zhuǎn)有點類似菲饼,主要用來指導(dǎo)框架層面的設(shè)計肾砂。高層模塊不依賴低層模塊,它們共同依賴同一個抽象宏悦。抽象不要依賴具體實現(xiàn)細節(jié)镐确,具體實現(xiàn)細節(jié)依賴抽象。
為何說KISS饼煞、YAGNI原則看似簡單源葫,卻經(jīng)常被用錯?
如何理解“KISS 原則”砖瞧?
KISS 原則:盡量保持簡單息堂。
YAGNI 跟 KISS 說的是一回事嗎?
YAGNI 原則:不要去設(shè)計當前用不到的功能块促;不要去編寫當前用不到的代碼瘟仿。實際上渠旁,這條原則的核心思想就是:不要做過度設(shè)計炕柔。
重復(fù)的代碼就一定違背DRY嗎象缀?如何提高代碼的復(fù)用性?
DRY 原則(Don’t Repeat Yourself)
DRY 原則:不要寫重復(fù)的代碼斋扰。
- 實現(xiàn)邏輯重復(fù)
- 功能語義重復(fù)
- 代碼執(zhí)行重復(fù)
怎么提高代碼復(fù)用性(Code Reusability)渡八?
- 減少代碼耦合
- 滿足單一職責(zé)原則
- 模塊化
- 業(yè)務(wù)與非業(yè)務(wù)邏輯分離
- 通用代碼下沉
- 繼承、多態(tài)传货、抽象屎鳍、封裝
- 應(yīng)用模板等設(shè)計模式
如何用迪米特法則(LOD)實現(xiàn)“高內(nèi)聚、松耦合”损离?
何為“高內(nèi)聚哥艇、松耦合”?
所謂高內(nèi)聚僻澎,就是指相近的功能應(yīng)該放到同一個類中貌踏,不相近的功能不要放到同一個類中。相近的功能往往會被同時修改窟勃,放到同一個類中祖乳,修改會比較集中,代碼容易維護秉氧。
所謂松耦合是說眷昆,在代碼中,類與類之間的依賴關(guān)系簡單清晰。即使兩個類有依賴關(guān)系亚斋,一個類的代碼改動不會或者很少導(dǎo)致依賴類的代碼改動作媚。
“高內(nèi)聚、松耦合”是一個非常重要的設(shè)計思想帅刊,能夠有效提高代碼的可讀性和可維護性纸泡,縮小功能改動導(dǎo)致的代碼改動范圍±德鳎“高內(nèi)聚”用來指導(dǎo)類本身的設(shè)計女揭,“松耦合”用來指導(dǎo)類與類之間依賴關(guān)系的設(shè)計。
“迪米特法則”理論描述
不該有直接依賴關(guān)系的類之間栏饮,不要有依賴吧兔;有依賴關(guān)系的類之間,盡量只依賴必要的接口(也就是定義中的“有限知識”)袍嬉。
迪米特法則是希望減少類之間的耦合境蔼,讓類越獨立越好。每個類都應(yīng)該少了解系統(tǒng)的其他部分冬竟。一旦發(fā)生變化欧穴,需要了解這一變化的類就會比較少。