關(guān)于組件化的那些事兒

前言:
先表一表寫這個(gè)博客的背景,愛奇藝知識(shí)項(xiàng)目的結(jié)構(gòu)之前也是采用組件化形式的,但是遺憾的是,前輩們拆分組件做的并不是很徹底,閱讀代碼和結(jié)構(gòu)來看,其實(shí)是很混亂的,由于結(jié)構(gòu)嚴(yán)重影響了打包的問題,在經(jīng)歷幾個(gè)迭代后,我們技術(shù)部終于忍無可忍,決定動(dòng)手對(duì)組件進(jìn)行重新整合拆分,一來可以使項(xiàng)目結(jié)構(gòu)更加清晰,二來有利于后續(xù)的項(xiàng)目維護(hù)和調(diào)試,三來也是最重要的,就是解決打包頻繁失敗報(bào)錯(cuò)的問題,畢竟解決眼前的問題才是最重要的。

言歸正傳,那么先來聊一聊關(guān)于組件化的一些理解,后面再結(jié)合拆分的例子詳細(xì)說明下拆分原則與組件間解耦的方式。

  1. 組件化是什么?

什么是組件化?這個(gè)問題是比較寬泛的,答案也多種多樣,關(guān)于網(wǎng)上大神們的定義和解答我也不再贅述,推薦個(gè)知乎上的一個(gè)帖子什么叫組件化開發(fā),這里只說一下自己的一點(diǎn)愚見:

組件,其實(shí)就是可插拔的一個(gè)功能模塊。詳細(xì)說來,就是組件其實(shí)就是為了方便快速開發(fā),將一些功能按需做成一個(gè)可獨(dú)立運(yùn)行,且可以快速集成到項(xiàng)目中的一個(gè)功能模塊。

它本身體現(xiàn)了設(shè)計(jì)原則中的高內(nèi)聚低耦合的特點(diǎn),這樣說可能有些人不明白,那舉個(gè)例子,登錄模塊(也可以叫登錄組件),對(duì)于項(xiàng)目A,有用到登錄功能,項(xiàng)目B也用到了,而且一般在一個(gè)公司,登錄的功能相似度都是非常高的,或者說是一致的。那么如果不用組件化,可能就需要在A,B中寫兩套登錄代碼,但如果有登錄模塊,那么只需要在A,B中分別引入登錄模塊,傳特定的參數(shù)即可實(shí)現(xiàn)登錄功能。以后有項(xiàng)目C,D,E,都可以類似這樣實(shí)現(xiàn),登錄模塊有修改的時(shí)候也只需要修改一份代碼就可以了。

但是有一點(diǎn)很重要,也是組件拆分中很難的一點(diǎn),就是對(duì)于組件功能的歸納和設(shè)計(jì),比如登錄模塊,你在設(shè)計(jì)組件的時(shí)候,就要考慮到不同APP的可定制化部分,那么登錄模塊其實(shí)只需要實(shí)現(xiàn)登錄內(nèi)核相關(guān)的部分即可,關(guān)于一些靈活的可定制的,可以放到業(yè)務(wù)層級(jí)去定制。

那么根據(jù)這個(gè)思路解釋,組件化其實(shí)就是將項(xiàng)目中的功能按分類進(jìn)行拆分成一個(gè)個(gè)靈活的基礎(chǔ)和功能模塊,調(diào)研過組件化的都知道組件化大致有基礎(chǔ)層,業(yè)務(wù)層,網(wǎng)絡(luò)層,路由層等等幾個(gè)層級(jí),具體項(xiàng)目中的組件拆分,結(jié)構(gòu)并不是一成不變的,我們不能死板地認(rèn)為組件就那幾個(gè)層,后面還會(huì)繼續(xù)說到這塊。

  1. 組件化該怎么實(shí)現(xiàn)?

關(guān)于組件化實(shí)現(xiàn)的方式,我理解的是有兩種:

2.1. 多target

多target更像是模塊化,將功能拆成一個(gè)個(gè)模塊,每一個(gè)模塊都是一個(gè)單獨(dú)的工程,只是木有做成Pod形式,在使用的時(shí)候只需要將所需的target拖到自己的工程項(xiàng)目中,配置好路徑即可,這樣做的弊端是需要配置路徑,開發(fā)環(huán)境配置較為麻煩。


截屏2021-10-09 下午2.55.01.png

上圖即為多target的形式,具體的實(shí)現(xiàn)方式不多做贅述

2.2. pod組件形式

這種就是經(jīng)常所用的類似第三方pod的形式,使用的時(shí)候只需要pod下來就行,比較靈活,下面來簡(jiǎn)單聊一聊如何用pod組件的方式實(shí)現(xiàn)組件化開發(fā)結(jié)構(gòu)

我之前的博客如何制作私有庫中有說明如何用pod形式制作私有庫的過程,博客寫的比較詳細(xì),使用的是先創(chuàng)建工程,再創(chuàng)建podspec的形式,下面我簡(jiǎn)單介紹些如何用pod lib create 的形式一氣呵成來制作pod組件庫

pod lib create 組件名

根據(jù)提示一路選擇下來,大致如下:


截屏2021-10-09 下午3.08.11.png
截屏2021-10-09 下午3.08.29.png

接下來會(huì)看到項(xiàng)目結(jié)構(gòu)如下:


截屏2021-10-09 下午3.11.19.png

我們所要做的組件內(nèi)容就應(yīng)該寫到Development Pods下, 如何讓別人也能通過pod下載到你的組件,就要依賴于podspec這個(gè)文件了,此文件中的具體編寫在如何制作私有庫這個(gè)博客中都有介紹,這里不做贅述

到這里,基本上本地的pod組件庫的制作就完成了,接下來是如何將你的組件關(guān)聯(lián)到云端,以供別人可用。
第三方的庫一般都是公有開源的,公司所用的組件一般是私有的,只有公司內(nèi)部可用的,一般將源碼放到gitlab上,在gitlab上如何創(chuàng)建私有索引庫,和私有代碼庫上述博客也有說明,這里補(bǔ)充一點(diǎn),如何將本地項(xiàng)目與云端的project結(jié)合:

git remote add origin 云端的project(源碼)地址
git add .
git commit -m '注釋說明'
git push -u origin master

這樣就完成了本地工程與云端源碼關(guān)聯(lián)

下一步就是將podspec上傳到gitlab中的索引管理倉庫
首先本地倉庫要打上對(duì)應(yīng)的tag值,這個(gè)tag值和podspec中的tag值要保持一致
其次podspec上傳:
這里有一點(diǎn)要注意,如何制作私有庫 此博客中關(guān)于 podspec的驗(yàn)證說的很詳細(xì),也附上了對(duì)應(yīng)的常見錯(cuò)誤處理,但是如果你制作的倉庫依賴了公司的其他庫,或者其他的第三方庫,可能有 lib lint失敗的情況,這個(gè)時(shí)候可以略過驗(yàn)證,手動(dòng)上傳(也可寫腳本執(zhí)行上傳操作)

說了這么多,總結(jié)的幾個(gè)命令如下:
pod lib create xxx
git remote add origin xxx
git add .
git commit -m 'xxx'
git push -u origin master
git tag tag值
git push origin tag值
上傳 podspec

  1. 組件化的分層到底該如何做?

關(guān)于組件化分層,一般是有基礎(chǔ)層,業(yè)務(wù)層網(wǎng)絡(luò)層,路由 這幾個(gè),但是在實(shí)際拆分中會(huì)發(fā)現(xiàn),如果嚴(yán)格按照這幾個(gè)層劃分,會(huì)很難去定位拆分結(jié)構(gòu),也有可能出現(xiàn)層級(jí)之前的依賴問題,那么關(guān)于如何去劃分層級(jí)結(jié)構(gòu),我這里做一下簡(jiǎn)要描述:

大體上的結(jié)構(gòu)還是常用的那些,只不過有一些小小的調(diào)整

  • 基礎(chǔ)層

這里的基礎(chǔ)層是那些不常動(dòng)的部分,比如計(jì)算字符串長度,文字顏色轉(zhuǎn)換方法,或者一些常用的工具類,有的文章是將基礎(chǔ)層和功能層分開來的,我這里覺得一些常用的工具類也可以作為基礎(chǔ)層沉淀下來,前提是此工具類和業(yè)務(wù)無關(guān)

  • 網(wǎng)絡(luò)層

這里與傳統(tǒng)的網(wǎng)絡(luò)層稍有不同,我們常說的網(wǎng)絡(luò)層是獨(dú)立存在,可能只需要依賴于基礎(chǔ)層和其他第三方即可,但是在實(shí)際開發(fā)中會(huì)發(fā)現(xiàn),我們可能需要額外對(duì)請(qǐng)求參數(shù)做一些處理,或者對(duì)網(wǎng)絡(luò)請(qǐng)求返回做些處理,那么這時(shí),網(wǎng)絡(luò)層就可以繼續(xù)細(xì)分為網(wǎng)絡(luò)核心層與通用網(wǎng)絡(luò)層(也可以叫通用層)。

網(wǎng)絡(luò)核心是真正的與其他業(yè)務(wù)無關(guān)的層級(jí),這里的通用網(wǎng)絡(luò)層可以理解為和網(wǎng)絡(luò)相關(guān),同時(shí)又和業(yè)務(wù)有關(guān)的層級(jí),那么你可能會(huì)說,那這個(gè)是不是可以放到業(yè)務(wù)層里面去?當(dāng)然是可以的,但是如果是類似 pingback(我們項(xiàng)目有用到,這個(gè)主要是數(shù)據(jù)上報(bào)的功能),因?yàn)樗鼈冇泻芏嘞嗤牡胤剑绻恳粋€(gè)單獨(dú)都放到業(yè)務(wù)層級(jí)處理,則會(huì)有許多的重復(fù)代碼出現(xiàn),所以可以考慮歸于網(wǎng)絡(luò)層中的通用網(wǎng)絡(luò)層。

在設(shè)計(jì)層級(jí)的時(shí)候并不是說一個(gè)層就是一個(gè)工程(一個(gè)組件),一個(gè)層可以有多個(gè)組件,那這里在設(shè)計(jì)網(wǎng)絡(luò)層的時(shí)候,就可以將網(wǎng)絡(luò)核心層與通用網(wǎng)絡(luò)層分成多個(gè)pod組件的形式

  • 通用業(yè)務(wù)層

比如項(xiàng)目中有用到類似微信,QQ這種需要配置一些appId, appKey的,或者是和項(xiàng)目業(yè)務(wù)有關(guān)的配置部分,如常量,通知名,顏色,字體(一般正規(guī)開發(fā)都會(huì)有一套顏色和字體以供使用),以及一些啟動(dòng)后的參數(shù)配置, push組件等。

  • 業(yè)務(wù)層

顧名思義,業(yè)務(wù)層就是一個(gè)個(gè)的業(yè)務(wù)功能,比如登錄,搜索,首頁,我的等等

  • 路由

主要是組件間的通信橋梁,一般常用在頁面間跳轉(zhuǎn),傳值及回調(diào)

其實(shí)簡(jiǎn)而言之,組件分層,并不是一成不變,每一個(gè)層可能又可以拆分出基礎(chǔ)層,通用層等,但有一點(diǎn)是一定的,那就是每一個(gè)基礎(chǔ)層一定都是相對(duì)而言較為靠下沉淀的,且組件間依賴的順序必須要遵循上層依賴下層,決不允許有反向依賴的情況,但是在實(shí)際開發(fā)中會(huì)遇到組件間的相互依賴問題,關(guān)于這個(gè)問題,下個(gè)模塊會(huì)詳細(xì)介紹.

  1. 組件化中組件間解耦的方式?

在設(shè)計(jì)組件的時(shí)候,一開始并不能一次性就能設(shè)計(jì)的很完美,那么就可能遇到B依賴了A組件,C依賴了B組件,但是A又依賴了C組件的相互依賴問題。如果是兩三個(gè)組件間的相互依賴還好,如果嵌套層級(jí)很多,還是從頭考慮下自己的組件結(jié)構(gòu)拆分是否有問題吧。

對(duì)于這種情況,主要是打破這個(gè)循環(huán),那么面向協(xié)議的方式就很有必要了。簡(jiǎn)單來說,就是在兩個(gè)組件之外有一個(gè)處理這兩個(gè)組件依賴的組件(可以是單獨(dú)的組件,也可以放到通用業(yè)務(wù)層的某個(gè)組件里面),簡(jiǎn)單說如下圖:

截屏2021-10-09 下午4.02.25.png

解耦組件中說白了就是協(xié)議,A,B兩個(gè)組件同時(shí)依賴與此組件,且遵循實(shí)現(xiàn)其中的協(xié)議即可

截屏2021-10-09 下午4.09.31.png

像這里的網(wǎng)絡(luò)層分為網(wǎng)絡(luò)組件和pingback組件以及協(xié)助這兩個(gè)組件解耦所用的中間組件,中間組件的實(shí)現(xiàn)

截屏2021-10-09 下午4.15.02.png

在網(wǎng)絡(luò)組件中的實(shí)現(xiàn)如下:

截屏2021-10-09 下午4.17.21.png
截屏2021-10-09 下午4.17.31.png

由于原有的代碼結(jié)構(gòu)讓pingback與網(wǎng)絡(luò)組件有相互依賴,這樣就能實(shí)現(xiàn),在網(wǎng)絡(luò)組件中對(duì)一些參數(shù)賦值,在pingback組件中使用到這些參數(shù)只需要傳遞一個(gè)遵循協(xié)議的id類型參數(shù)就可以了。

其他的組件相互依賴的問題,可以用類似的方式解決。

  1. 路由(注冊(cè)制)

路由的話題已經(jīng)有很多博客中提及到,蘑菇街的URL注冊(cè)制方式,target-action,protocol 協(xié)議等諸多方式都可以實(shí)現(xiàn)。

我們項(xiàng)目中使用的是注冊(cè)制,簡(jiǎn)而言之也就是在項(xiàng)目中有一個(gè)plist文件,規(guī)定好參數(shù)及其對(duì)應(yīng)的值,由后端下發(fā)map,去plist中映射出需要跳轉(zhuǎn)的目的落地頁(有相關(guān)字段對(duì)應(yīng)),將對(duì)應(yīng)的參數(shù)打包成一個(gè)字典傳遞過去即可。

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

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

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