臃腫走開之組件化取經(jīng)之路

近幾年組件化大家吵的沸沸揚(yáng)揚(yáng)的,它其實(shí)也不是什么黃金圣衣,穿上立馬讓你的小宇宙提升幾個檔次,也不是海皇的三叉戟,入手就能呼風(fēng)喚雨,它不過就是一種app的架構(gòu)思路。其實(shí)真的很簡單,如果你的項目從發(fā)布之初就是用組件化,那么在開發(fā)的過程當(dāng)中勢必會少很多麻煩,難點(diǎn)其實(shí)是對我們龐大古老的工程進(jìn)行組件化的改造。

一.下面我們來談?wù)劷M件化到底是什么

其實(shí)組件化說白了就是將一個單一的工程分解為各個獨(dú)立的組件,然后按照某種方式任意組織成為一個擁有完整業(yè)務(wù)邏輯的工程。

舉個例子大家就明白了,一輛完整的汽車從來都不是由一個工廠將所有的零部件生產(chǎn)完成的,而是輪胎廠生產(chǎn)輪胎,發(fā)動機(jī)廠生產(chǎn)發(fā)動機(jī),玻璃廠生產(chǎn)玻璃等等,然后再組裝成為一輛完整的汽車。我們的各個組件或者說模塊就是汽車的各個零部件,我們的整個工程我們也把它叫做宿主工程就是我們的汽車,我們按照一定的規(guī)則把他們拼裝起來就是一個業(yè)務(wù)邏輯完整的工程。

二.組件化產(chǎn)生的原因

那么組件化為何應(yīng)運(yùn)而生,其實(shí)在我們的開發(fā)過程中,如果本身項目的規(guī)模不大,業(yè)務(wù)線比較少,人員也比較少,我們使用一般的單一開發(fā)模式就好了。但是隨著我們的項目不斷的迭代更新,業(yè)務(wù)線越來越多,發(fā)開人員也組件增多,這個時候就會暴露各種各樣的問題

※.耦合性嚴(yán)重

※.編譯速度慢

※.測試不獨(dú)立

※.無法使用自己擅長的設(shè)計模式

......

※.耦合性嚴(yán)重

關(guān)于耦合性嚴(yán)重這點(diǎn)舉個大家深有體會的例子,我們對接手二手甚至N手項目的時候都是深惡痛絕的,因為我們不知道以前的開發(fā)人員的思路和架構(gòu),這個時候我們往往面臨著三類問題

1.代碼的重構(gòu)

2.增加新功能

3.改bug

就拿我們改bug來說,我們由于不了解人家的思路,我們把面前的bug改掉了,結(jié)果我們出了更多得bug,越改越多,頭疼至極,因為我們可能將眼前bug改掉的同時,其他同樣依賴改動地方的代碼卻不適用了,這就非常尷尬了。

同樣地對我們的新功能開發(fā)和代碼重構(gòu)也是如此,我們好不容易將自己的功能模塊搞定的時候,由于對老模塊有依賴,一旦老模塊中存在某些bug,會導(dǎo)致我們整個工程都跑不起來,我們不但測試不了自己新寫的功能模塊,而且我們可能連bug在哪都不是一時半會兒就找到的,再加上解決的時間我們將耗費(fèi)大量的時間和精力,大大降低了我們的發(fā)開效率。

※.編譯速度慢

隨著工程的業(yè)務(wù)線越來越多,發(fā)開人員不斷增加,我們的項目越來越龐大,往往項目編譯少則一兩分鐘多則幾分鐘,雖然并不影響我們的開發(fā)工作,但是我們使用組件化的開發(fā)配合二進(jìn)制化,我們完全可以提高整個項目的編譯時間。

※.測試不獨(dú)立


從這張圖我們能看到我們在發(fā)開完畢我們自己的模塊之后,我們需要對自己的模塊進(jìn)行測試,但是主工程里面的其他模塊存在一個bug,導(dǎo)致我們的工程編譯不了,那么我們開發(fā)的模塊勢必也是測試不了的,真的很尷尬。

※.無法使用自己擅長的設(shè)計模式

這個我們稍微說一下大家應(yīng)該能明白,如果你的公司主要是使用MVVM的架構(gòu)模式進(jìn)行開發(fā)的,而你只會使用MVC進(jìn)行開發(fā),是不是很尷尬,當(dāng)然我們可以按照MVC去套用MVVM進(jìn)行開發(fā),但是我給大家畫一張圖大家就明白了

假設(shè)說我們的設(shè)計模式按照模塊劃分的話,我們沒法使用MVC去套用我們的MVVM,這樣我們除了去學(xué)習(xí)MVVM之外別無他法,可關(guān)鍵是你真的有足夠的時間在短時間內(nèi)上手嗎?

當(dāng)然如果我們按照功能模塊來劃分的話,我們的MVC倒是可以套用我們的MVVM,但是你能保證不出問題嗎?

三.組件化的優(yōu)勢

那么我們使用組件化之后到底能達(dá)到什么樣的效果呢?

※組件的獨(dú)立

我們終于可以獨(dú)立編寫我們的模塊,獨(dú)立編譯而不用漫長的等待主工程長達(dá)數(shù)分鐘的編譯,我們再也不用擔(dān)心因為各種非自己功能模塊中的bug讓我們寸步難行無法單獨(dú)測試了。

※資源的重用

我們項目中各種分類,宏定義,基礎(chǔ)配置這些基礎(chǔ)的代碼,以及我們的輪播器,選項卡等等這些功能性的自定義UI組件再也不用重復(fù)的拖取或者重寫,我們只需要以pod庫的形式直接導(dǎo)入到工程中就OK啦。

※高效的迭代

當(dāng)我們需要增加或者刪除某些模塊,我們只需要將對應(yīng)的路徑刪除掉,就可以一次性將整個模塊增加或者移除又不會影響宿主工程的正常運(yùn)行,十分高效。

※配合二進(jìn)制,可大大提高項目的編譯速度

我們把業(yè)務(wù)性、功能性、基礎(chǔ)性的模塊拆分成組件以后,可以采用靜態(tài)庫打包,framework庫的形式二進(jìn)制化組件,這樣將大大提高我們的編譯速度。

四.組件化應(yīng)該考慮的問題

※組件的劃分

我們一般將組件劃分為三類

基礎(chǔ)組件:

包含基本配置(常量,宏)、分類(各種系統(tǒng)類的擴(kuò)展)、網(wǎng)絡(luò)(AFN、SDWebImage封裝)、工具(日期時間處理、文件處理、設(shè)備信息等)


功能組件:

包含控件(彈幕、輪播器、選項菜單、圖文菜單等)、功能(斷點(diǎn)續(xù)傳、音頻處理等)


業(yè)務(wù)組件:

業(yè)務(wù)線一(子業(yè)務(wù)線一,子業(yè)務(wù)線二.....)

業(yè)務(wù)線二(子業(yè)務(wù)線一,子業(yè)務(wù)線二.....)


※組件層級之間的關(guān)系

從這張圖我們可以看出來,我們?nèi)蠼M件類,其實(shí)是有層級關(guān)系的,我們的業(yè)務(wù)組件既要使用我們的基礎(chǔ)組件也要使用我們的功能組件,它屬于我們基礎(chǔ)組件和功能組件的上一層,而我們的基礎(chǔ)組件和功能組件屬于同一層級,他們之間是不能互相產(chǎn)生依賴關(guān)系的。

如果說我們的功能組件的彈幕需要使用到基礎(chǔ)組件中的有關(guān)布局View的分類,我們這個時候最好的做法并不是將讓我們的功能組件依賴于我們的基礎(chǔ)組件,這樣的話別人要使用我們的彈幕卻要將我們整個基礎(chǔ)組件都下載下來,那么我們的組件化就失去了原有的意義。我們在這里推薦的做法是講我們所需要的那塊代碼直接拷貝到我們的功能組件當(dāng)中去,這樣做的好處在于我們的功能組件不需要依賴我們的基礎(chǔ)組件。

同樣在我們?nèi)蠼M件類的內(nèi)部,組件之間也不能產(chǎn)生依賴關(guān)系,好比我們的彈幕不能依賴于我們的播放器,總不能別人要使用我們的彈幕還得把播放器給下載下來把,這樣也是不合理的,對我們業(yè)務(wù)組件也是一樣的,我們要增加或者刪除某個業(yè)務(wù)線,結(jié)果導(dǎo)致其他的業(yè)務(wù)線沒法正常的使用了,這都是不可取的。

但是某些時候我們確實(shí)需要使用其他組件里面的內(nèi)容,但是他們之間又不能產(chǎn)生依賴關(guān)系,這個時候我們就要使用到組件間的通訊,這個在后面會講到組件間如何通訊。


※組件的存在形式

組件內(nèi)部:根據(jù)設(shè)計模式劃分文件夾結(jié)構(gòu)

組件形式(對外):每個組件都是以pod庫的形式存在

組件測試:單獨(dú)的測試工程(這里我們可以通過創(chuàng)建pod模板庫形式,直接擁有測試工程)


※我們是以Cocoapods的形式安裝各個組件的

這張圖我們可以看到,我們的業(yè)務(wù)組件是可以依賴我們的基礎(chǔ)組件和我們的功能組件的,而我們的業(yè)務(wù)組件都是以pod庫的形式借助我們Cocoapod安裝到我們宿主工程中去,我們的宿主工程面向的都是我們的業(yè)務(wù)組件。


※組件間的通訊

上面提到了我們同層次間的組件或者是我們?nèi)蠼M件內(nèi)部的組件之間是不能有依賴關(guān)系的,但是確實(shí)有些時候我們一個組件內(nèi)部發(fā)生了一些事件想要告訴其他組件,或者需要調(diào)用某些組件的服務(wù),這個時候我們就需要用到組件之間的通訊。

這里我們來講講其中的一種方式--中間件,我們用一張示意圖來描述一下


在這里我們看到我們組件都是通過中間件來進(jìn)行交互的,組件將內(nèi)部發(fā)生的變化告訴給中間件,中間件在通知其他組件。我們組件把各自的服務(wù)給中間件,需要對應(yīng)服務(wù)的組件就會去找中間件拿,這樣的話我們組件之間不會產(chǎn)生依賴關(guān)系,同時又能進(jìn)行通訊。

五.分離組件的難點(diǎn)--解耦

一般在組件化的分離各個組件的時候,解耦這個話題我們是回避不了的,但是其實(shí)我們一般會遇到兩種情況

1.組件里面依賴其他公共功能

2.組件內(nèi)部需要對接某個服務(wù)

組件里面依賴其他公共功能

對于這種情況,我們一般最快的方式就是直接copy代碼,雖然這個過程比較惡心,但是好處就是不會有額外的依賴,對于一些不重要的工具方法,我們都可以拷貝到內(nèi)部來使用。

舉個例子大家都明白了,我們使用獲取屏幕尺寸的方法,而這個方法我們一般寫成宏定義放在我們的基礎(chǔ)組件中,我們的業(yè)務(wù)組件中要用到這個方法沒這個時候我們沒必要把我們基礎(chǔ)組件也整個下載下來,我們直接復(fù)制粘貼這短代碼就好了。

我們也可以把組件依賴的代碼先做成一個pod庫,然后依賴這個pod庫就好了,這樣我們的問題就迎刃而解了。

組件內(nèi)部需要對接某個服務(wù)

比如我們控件的內(nèi)部涉及到加載網(wǎng)絡(luò)圖片,我們一般會用到我們的SDWebImage的框架,雖然我們可以在使用遠(yuǎn)程私有索引庫的時候添加依賴,那么我們在下載我們的私有庫里面組件的時候我們可以將SDWebImage一并集成到我們的宿主工程中。如果開發(fā)過程中,公司用得不是SDWebImage不是會很尷尬嗎?

所以我們使用的方式就是使用block或者代理把這部分職責(zé)丟出去,那么我們就可以自用的選擇我們所需要使用的第三方框架或者公司內(nèi)部寫的框架,不用再糾結(jié)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容