功能:比如一個ImageLoader,負責實現(xiàn)圖片加載,但是要支持緩存;那么這個ImageLoader就是我們討論的功能;
依賴:上述ImageLoader功能,需要支持緩存,但是緩存其實也是一個很大的功能,而且會有多種策略,那么ImageLoader就不應該把緩存功能緊耦合,而是作為一個外部的依賴;
使用者:上述ImageLoader作為一個功能,可以打包成一個庫,那么用這個庫的APP就是使用者;
使用者的需求是經(jīng)常變化的,因為他們的業(yè)務會隨著迭代而不斷調(diào)整,那么ImageLoader這個功能好的實現(xiàn)就是無論使用者的需求怎么變化,都無需改變ImageLoader這一功能的實現(xiàn)。但是對于緩存這一核心特性,也應該做到按需定制,而無需改變ImageLoader的實現(xiàn)代碼;
非常直觀的,一個類越簡單,就越難有bug,50行代碼基本不可能有bug,即便出了bug,也很容易分析出來,甚至都不用調(diào)試。
所以,盡可能的拆分,盡可能地簡化一個類的職責,并且聚焦于這個單一的職責。一個類只聚焦于自己的職責時,需要修改一個功能,那么被修改的類也就會盡可能的少了。
抽象來說,就是“對擴展開放,對修改封閉”。具體點,就是功能的修改、增加,盡可能通過增加新的類(擴展)來實現(xiàn),而不是修改已有的類。
但是如何達到這個效果?就是盡量把可能會變動的地方抽象出來,使用接口進行依賴,具體的實現(xiàn)通過依賴注入來耦合。這樣,修改功能就是增加新的實現(xiàn),在使用者的代碼里面注入新的實現(xiàn)。使用者的需求變了,代碼的修改是不可避免的,但是功能的框架,如果能不修改,那就降低了引入bug的可能性。
所有引用基類的地方必須能透明地使用其子類的對象。滿足此條件時,對依賴的聲明(成員、參數(shù))都通過抽象基類來完成,則使用新的實現(xiàn)類時,只需替換注入/傳遞的參數(shù)即可,功能實現(xiàn)無需改變。更進一步,使用接口聲明依賴,能一定程度上避免繼承引入的問題。
客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。根據(jù)接口隔離原則,當一個接口太大時,我們需要將它分割成一些更細小的接口,使用該接口的客戶端僅需知道與之相關的方法即可,可以達到屏蔽其他接口可見性的效果。
模塊間的依賴通過抽象發(fā)生,抽象即抽象類或者接口;使用接口更佳,而且接口內(nèi)不要定義任何數(shù)據(jù);
一個類應該對自己依賴(使用)的其他類知道得最少,所謂知道,就是使用??梢灶惐冉涌诟綦x原則,依賴盡可能少的接口,每個接口又僅僅包含確實和自己的功能相關的方法。