OOP的六大原則——Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)讀書筆記

更好的代碼

我總在思考如何讓自己寫成更優(yōu)雅的代碼,如何寫出更易維護(hù)诵姜,更易讀懂的代碼汽煮,我覺得很幸運(yùn),第一份實(shí)習(xí)工作棚唆,在很大程度上幫助了我暇赤,但后來(lái)其實(shí)我發(fā)現(xiàn)我學(xué)到只是一些皮毛,還有更多需要學(xué)習(xí)的宵凌,所以為了寫出更簡(jiǎn)潔鞋囊,更易他人讀懂的代碼,我開始接觸兩本書瞎惫,一本書現(xiàn)在這里寫讀書筆記的這本書溜腐,另一本是很著名的代碼整潔之道,那么我們來(lái)介紹一下這兩本書微饥。

Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)這本書主要講了面向?qū)ο?下面統(tǒng)稱OOP)的六大原則逗扒,23種設(shè)計(jì)模式以及MVC和MVP這兩種應(yīng)用架構(gòu)去看待應(yīng)用開發(fā)。

當(dāng)我們開始了解并遵守OOP的六大原則時(shí)欠橘,我們可以寫出更易擴(kuò)展更簡(jiǎn)潔的代碼矩肩,并了解到為什么這樣做更好,其實(shí)Java在面向?qū)ο缶幊痰那疤嵯滤嘈覀儜?yīng)該更多的是面向抽象編程黍檩,而這里抽象既包括了抽象類也包括了接口。

23種設(shè)計(jì)模式可以讓我們了解到如何更好的更簡(jiǎn)單的解決一個(gè)問題始锚,但是有時(shí)候大家卻在濫用設(shè)計(jì)模式刽酱,所以如何平衡使用也是需要學(xué)習(xí)的。

而最后講的MVC和MVP我們也應(yīng)該更多的了解瞧捌,Android本身就采用了MVC模式棵里,而MVP模式這兩年也被運(yùn)用的比較廣泛,以至于官方都推出一個(gè)MVP的DEMO姐呐,從而統(tǒng)一大家的書寫習(xí)慣和對(duì)MVP的理解殿怜。

代碼整潔之道這本書其實(shí)我還沒開始看,但之前在別的公司讀過一部分曙砂,看到一句話头谜,讓我印象深刻,第一章作者用每個(gè)人角度討論了什么是更好的代碼鸠澈,讓我印象深刻那句話是這樣的——什么的代碼是最好的柱告,就是每當(dāng)我覺得代碼可以進(jìn)行修改和完善的時(shí)候截驮,我最后總是回到起點(diǎn)。

我非常認(rèn)同寫代碼就像寫文章這個(gè)觀點(diǎn)际度,更多時(shí)候我們不是寫給自己看的葵袭,所以可以做到讓其他人一眼就能看懂你在講什么,實(shí)現(xiàn)了什么功能才是我們需要做的甲脏,這就涉及到很多要做好的事情眶熬,更好的命名,更簡(jiǎn)潔的函數(shù)块请,職責(zé)單一的類娜氏,易擴(kuò)展的設(shè)計(jì)等等。

OOP六大原則

作者在講述的時(shí)候很生動(dòng)墩新,舉一系列例子贸弥,使得我們更好地理解它講述出來(lái)的六大原則,那我么下面我們就來(lái)看看OOP的六大原則到底如何運(yùn)用和他們起到的作用海渊。

1.單一職責(zé)原則

定義:就一類而言绵疲,應(yīng)該僅有一個(gè)引起它變化的原因。

作者給了另一個(gè)概括臣疑,一個(gè)類中應(yīng)該是一組相關(guān)性很高的函數(shù)盔憨、數(shù)據(jù)的封裝,也就是說一個(gè)類它只做一件事讯沈,我并不想成為一個(gè)神一樣的類(什么功能都有什么都可以做)郁岩,而只是我負(fù)責(zé)一件事,我把它做的很好缺狠,所以我們首先要思考的是我寫這個(gè)類他的職責(zé)是什么问慎?這有時(shí)候總是不能清晰的界定,導(dǎo)致了我們寫出類并沒有很好遵守這個(gè)原則挤茄。

作者在舉例的時(shí)候講了一個(gè)很實(shí)在的例子如叼,讓一個(gè)新手去實(shí)現(xiàn)一個(gè)ImageLoader,而他很快就寫好了穷劈,交給主管去看笼恰,主管卻不是很滿意,因?yàn)樗言趫D片加載的類中同時(shí)做了兩件事情歇终,一個(gè)是加載的圖片社证,一個(gè)是對(duì)圖片緩存,而主管看到后表示了不滿练湿,希望他可以把代碼拆分猴仑,把各個(gè)功能獨(dú)立出來(lái)审轮,所以在修改后他就把圖片的加載和圖片的緩存分成了兩個(gè)不同的類肥哎,讓它們只負(fù)責(zé)一件事辽俗。
而這例子很好的解釋了什么是單一職責(zé)原則,一個(gè)多功能的類篡诽,拆分成若干個(gè)單一功能的類崖飘,從而降低了代碼耦合。

2.開閉原則

定義:軟件中的對(duì)象(類杈女、模塊朱浴、函數(shù)等)應(yīng)該對(duì)擴(kuò)展開放,但是达椰,對(duì)于修改應(yīng)該是封閉的翰蠢。

作者講到我們?cè)陂_發(fā)過程中,需求總是會(huì)有變化啰劲,所以代碼也就免不了進(jìn)行相應(yīng)的改變梁沧,而這條原則告訴我們盡量不是通過修改原有代碼來(lái)實(shí)現(xiàn)新需求而是對(duì)現(xiàn)有功能進(jìn)行擴(kuò)展來(lái)應(yīng)對(duì)需求的變化。我們說到擴(kuò)展可能會(huì)想要繼承蝇裤,實(shí)現(xiàn)廷支,加入新的類,理想的情況是只通過這這幾種方式來(lái)完成栓辜,但實(shí)際情況可能是這幾方式的同時(shí)也伴隨著對(duì)原有代碼的的修改恋拍。

作者在書中還引用了《面向?qū)ο筌浖?gòu)造》作者的話,因?yàn)槭撬岢隽碎_閉原則藕甩,——程序一旦開發(fā)完成施敢,程序中一個(gè)類(原有代碼)的實(shí)現(xiàn)只應(yīng)該因?yàn)殄e(cuò)誤而被修改,新的或者改變的特性應(yīng)該通過新建不同的類實(shí)現(xiàn)辛萍,新建的類可以通過繼承的方式來(lái)重用原有的代碼(可以看出提出開閉原則的人提倡實(shí)現(xiàn)繼承)悯姊。

作者在上一個(gè)例子的基礎(chǔ)上舉了一個(gè)例子,那個(gè)新手已經(jīng)完成了圖片加載和圖片緩存的拆分贩毕,但隨著用戶的增多悯许,有些問題也就暴露了出來(lái),它之前只是使用了內(nèi)存緩存辉阶,所以當(dāng)內(nèi)存緩存的內(nèi)容被清理時(shí)先壕,用戶就只能再次下載圖片,就導(dǎo)致了圖片加載緩慢和消耗用戶流量谆甜,此時(shí)應(yīng)該考慮把圖片緩存到本地垃僚,這樣就解決了內(nèi)存緩存被清理的問題,不必再去重新下載圖片规辱。

而他只是添加一個(gè)新的類谆棺,然后在圖片緩存類里面加入使用,通過判斷使用哪種方式緩存罕袋,此時(shí)主管又給出意見改淑,用戶可以自己決定使用哪種緩存碍岔,單獨(dú)使用某一個(gè)或者同時(shí)使用兩種緩存。而其實(shí)最好的緩存策略其實(shí)是同時(shí)使用朵夏,但是優(yōu)先使用內(nèi)存緩存的蔼啦,如果被清理了再去查看本地緩存是否存在。

此時(shí)他已經(jīng)寫了三個(gè)關(guān)于內(nèi)存緩存的類了仰猖,內(nèi)存緩存捏肢,本地緩存,雙緩存饥侵,代碼如下鸵赫,主管看到代碼告訴了他不能每次加入新緩存你都去修改原有代碼,這樣很容易引入Bug躏升,且會(huì)使得邏輯越來(lái)越復(fù)雜奉瘤,因?yàn)橐ㄟ^條件判斷到底需要使用哪種緩存,主管給他講解了開閉原則煮甥,但是作為新手他并不理解盗温,有點(diǎn)云里霧里的,不知如何下手成肘,所以主管親自修改了代碼卖局。

//  新手的代碼
public class ImageLoader {
    //  內(nèi)存緩存
    ImageCache mImageCache = new ImageCache();
    //  本地緩存
    DiskCache mDiskCache = new DiskCache();
    //  雙緩存
    DoubleCache mDoubleCache = new DoubleCache();
    
    //  ....省略下面代碼
}
//  主管的代碼
//  首先提取出了一個(gè)圖片緩存接口
public interface ImageCache {
    void put(String url, Bitmap bitmap);
    Bitmap get(String url);
}

//  然后分別實(shí)現(xiàn)了MemoryCache,DiskCache双霍,DoubleCache砚偶,代碼省略

public class ImageLoader {
    //  圖片緩存,并設(shè)置了內(nèi)存緩存為默認(rèn)方式
    private ImageCache mImageCache = new MemoryCache();
    
    //  注入緩存實(shí)現(xiàn)  利用了向上轉(zhuǎn)型
    public void setImageCache(ImageCache imageCache) {
        mImageCache = imageCache;
    }

    //  省略其他成員變量和方法    
}

//  使用方法  只是通過傳入不同實(shí)現(xiàn)就可以切換緩存方式
ImageLoader loader = new ImageLoader();
loader.setImageCache(new MemoryCache());
loader.setImageCache(new DiskCache());
loader.setImageCache(new DoubleCache());

我們看得到通過setImageCache(ImageCache imageCache) 方式注入不同的緩存實(shí)現(xiàn)洒闸,使得ImageLoader代碼變得更簡(jiǎn)單染坯,健壯,提升高了它的靈活性和可擴(kuò)展性丘逸,如果還有還有新的緩存方式单鹿,只需要去實(shí)現(xiàn)ImageCachej接口就可以使用了。

所以當(dāng)需求發(fā)生變化時(shí)深纲,應(yīng)該盡量通過擴(kuò)展的方式來(lái)實(shí)現(xiàn)變化仲锄,而不是通過修改已有代碼來(lái)實(shí)現(xiàn),但要做到開閉原則湃鹊,首先我們應(yīng)該先寫出更易擴(kuò)展的代碼儒喊。

3.里氏替換原則

定義:所有引用的基類的地方都必須能透明的使用其子類的對(duì)象。
作者用了一句很通俗的話講解了這個(gè)原則——只要父類能出現(xiàn)打的地方之類就可以出現(xiàn)币呵。

就像開閉原則中舉的例子怀愧,主管修改了代碼,創(chuàng)建了一個(gè)ImageCache,而其他緩存類都是他的實(shí)現(xiàn)類芯义,而setImageCache(ImageCache imageCache) 需要的就是ImageCache類型肛搬,這時(shí)候我們就可以使用MemoryCache,DiskCache毕贼,DoubleCache來(lái)替換ImageCache的工作。ImageCache確定了規(guī)范蛤奢,而新的緩存需求都可以通過實(shí)現(xiàn)它然后替換ImageCache來(lái)工作鬼癣,從而保證了可擴(kuò)展性。

故里氏替換原則就是通過建立抽象啤贩,建立規(guī)范待秃,然后在運(yùn)行時(shí)通過具體實(shí)現(xiàn)來(lái)替換掉抽象,從而保證了系統(tǒng)的擴(kuò)展性和靈活性痹屹≌掠簦可見,在開發(fā)過程中運(yùn)用抽象是走向代碼優(yōu)化的重要一步志衍。

開閉原則和里氏替換原則往往都是一同出現(xiàn)的暖庄,通過里氏替換原則達(dá)到對(duì)擴(kuò)展的開發(fā),對(duì)修改關(guān)閉的效果楼肪。

4.依賴倒置原則

定義:指代了一種特定形式的解耦形式培廓,使得高層次的模塊不依賴于低層次的模塊的實(shí)現(xiàn)細(xì)節(jié)的目的,依賴模塊被顛倒了春叫。

依賴倒置原則的三個(gè)關(guān)鍵點(diǎn):
(1).高層次模塊不應(yīng)該依賴于底層模塊肩钠,兩者都應(yīng)該依賴其抽象;
(2).抽象不應(yīng)依賴細(xì)節(jié)暂殖;
(3).細(xì)節(jié)應(yīng)該依賴抽象价匠。

接下來(lái)作者解釋了一些概念:抽象就是指接口或者抽象類;細(xì)節(jié)就是實(shí)現(xiàn)類呛每;高層模塊就是調(diào)用端踩窖,低層模塊就是具體實(shí)現(xiàn)類。

所以作者說依賴倒置原則在Java中表現(xiàn)就是:模塊間依賴是通過抽象發(fā)生的晨横,實(shí)現(xiàn)類之間并不產(chǎn)生直接依賴關(guān)系毙石,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的。
一句話概括:面向接口編程颓遏,或者說面向抽象編程徐矩。

我們依然可以通過上面的例子繼續(xù)說明,代碼如下:

//  如果在ImageLoader中直接這樣寫的話
//  就是直接依賴于細(xì)節(jié)(直接依賴實(shí)現(xiàn)類)
private DoubleCache mImageCache = new DoubleCache();
//  而主管的代碼卻直接完成1.2.3.4這是個(gè)原則
//  依賴于抽象叁幢,通過向上轉(zhuǎn)型滤灯,有一個(gè)默認(rèn)的實(shí)現(xiàn)類
private ImageCache mImageCache = new MemoryCache();

//  設(shè)置緩存策略,依賴于抽象
public void setImageCache(ImageCache imageCache) {
    mImageCache = imageCache;
} 

依賴于抽象,依賴于基類鳞骤,這樣當(dāng)需求發(fā)生變化窒百,只需要實(shí)現(xiàn)ImageCache或者繼承已實(shí)現(xiàn)的之類都可以完成緩存功能,然后將實(shí)現(xiàn)注入到setImageCache(ImageCache imageCache)就可以了豫尽。

5.接口隔離原則

定義:客戶端不應(yīng)該依賴它不需要的接口篙梢。或者說類的依賴關(guān)系應(yīng)該將在最小的接口上美旧。

作者說接口隔離的目的是系統(tǒng)接口耦合渤滞,從而容易重構(gòu)、更改和重新部署榴嗅。一句話:讓客戶端以來(lái)的接口盡可能小妄呕。

作者舉了一個(gè)例子,當(dāng)我們?cè)谑褂昧鞯臅r(shí)候我們需要在finally中判斷是否為空嗽测,如果不為空需要close()它绪励,但每次使用流,都這么寫唠粥,也會(huì)讓代碼變得不優(yōu)美疏魏,這個(gè)時(shí)候我們考慮借助外力,就比如Java為我們提供了一個(gè)Closeable接口晤愧,而它有100多個(gè)實(shí)現(xiàn)類蠢护,所以那些類都可以使用它,代碼如下:

//  這就是修改之前的代碼 try/catch中還有try/catch
FileOutputStream fileOutputStream = null;
try {
//  邏輯省略
} catch (Exception e) {
        e.printStackTrace();
} finally {
        if (fileOutputStream != null) {
                try {
                        fileOutputStream.close();
               } catch (IOException e) {
                        e.printStackTrace();
               }
        }
}

//  寫了個(gè)CloseUtil類养涮,然后西面提供這個(gè)靜態(tài)方法葵硕,所有實(shí)現(xiàn)了Closeable的類都可以調(diào)用這個(gè)方法
 public static void closeQuietly (Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}

//  我們只需要在finally中調(diào)用這一句話就好了
CloseUtil.closeQuietly(xxx);

不僅讓代碼的可讀性增加了,還保證了它的重用性贯吓,這里也用到了依賴倒置原則懈凹,closeQuietly()方法的參數(shù)就一個(gè)抽象,做到了我只需要知道這個(gè)對(duì)象是可關(guān)閉的悄谐,其他一概不管辛介评,也就是作者所說的接口隔離原則。

6.迪米特原則

定義:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象有最少的了解爬舰。

通俗的講们陆,一個(gè)類應(yīng)該對(duì)自己需要耦合或者調(diào)用的類知道的最少,類的內(nèi)部如何實(shí)現(xiàn)與調(diào)用者或者依賴者沒有關(guān)系情屹,只需要知道它需要的方法即可坪仇,其他的一概不管,類與類之間的關(guān)系越密切垃你,耦合度也就越大椅文。

迪米特原則還有一個(gè)英文解釋:Only talk to your immediate friends.翻譯過來(lái)也就是說之與直接朋友進(jìn)行通信喂很。

作者舉了例子方便我們理解,現(xiàn)在有三個(gè)類皆刺,一個(gè)是房間類少辣,中介類以及租客類,租過房子的朋友都應(yīng)該知道羡蛾,中介手里是有很多是房子的漓帅,而我們想要找什么樣的房子只要告訴中介條件,他就會(huì)幫你找到合適的房子痴怨,這里也是忙干,在租客類眼中他的直接朋友就是中介類,我所有的找房子腿箩,打掃房間,修電器劣摇,交水電費(fèi)都找他一個(gè)類就可以珠移,因?yàn)樗麜?huì)幫我們都搞定,至于房東長(zhǎng)什么樣子末融,房產(chǎn)證放在哪里了租客就都不需要關(guān)心了钧惧,這樣就形成了租客只和中介打交道,而中介管理者房屋列表勾习,這也就是迪米特原則浓瞪。

上面就是OOP的六大原則,我講的還是太啰嗦了巧婶,希望通過更多的寫作乾颁,可以改善自己的表達(dá),也希望可以把自己學(xué)到的知識(shí)通過自己表述講給他講聽艺栈。Android源碼設(shè)計(jì)模式卻是一本好書英岭,希望大家也可以讀一讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末湿右,一起剝皮案震驚了整個(gè)濱河市诅妹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌毅人,老刑警劉巖吭狡,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丈莺,居然都是意外死亡划煮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門缔俄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)般此,“玉大人蚪战,你說我怎么就攤上這事☆戆茫” “怎么了邀桑?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)科乎。 經(jīng)常有香客問我壁畸,道長(zhǎng),這世上最難降的妖魔是什么茅茂? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任捏萍,我火速辦了婚禮,結(jié)果婚禮上空闲,老公的妹妹穿的比我還像新娘令杈。我一直安慰自己,他們只是感情好碴倾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布逗噩。 她就那樣靜靜地躺著,像睡著了一般跌榔。 火紅的嫁衣襯著肌膚如雪异雁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天僧须,我揣著相機(jī)與錄音纲刀,去河邊找鬼。 笑死担平,一個(gè)胖子當(dāng)著我的面吹牛示绊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播暂论,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耻台,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了空另?” 一聲冷哼從身側(cè)響起盆耽,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扼菠,沒想到半個(gè)月后摄杂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡循榆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年析恢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秧饮。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡映挂,死狀恐怖泽篮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柑船,我是刑警寧澤帽撑,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鞍时,受9級(jí)特大地震影響亏拉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逆巍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一及塘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锐极,春花似錦笙僚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至檬嘀,卻和暖如春槽驶,著一層夾襖步出監(jiān)牢的瞬間责嚷,已是汗流浹背鸳兽。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罕拂,地道東北人揍异。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爆班,于是被迫代替她去往敵國(guó)和親衷掷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容