iOS代碼的taste(品味)
最近看了不少代碼,想起寫代碼有意思的地方之一在于,實(shí)現(xiàn)同一個(gè) feature,修復(fù)同一個(gè) bug,不同程序員可以寫出風(fēng)格迥異的代碼,甚至流程也不同,雖然最后都可行,從結(jié)果論的角度對(duì)用戶來(lái)說(shuō)是一致的。我們可以稱這種差異為個(gè)人 taste,taste 有好壞高低之分,但有時(shí)候如何評(píng)定卻很難有一個(gè)清晰準(zhǔn)確的界定標(biāo)準(zhǔn),一般來(lái)說(shuō)代碼是越簡(jiǎn)單越清晰越容易測(cè)試越好,但簡(jiǎn)單清晰容易測(cè)試又是另一個(gè)維度的標(biāo)準(zhǔn),又會(huì)產(chǎn)生分歧,真要較真起來(lái)可以無(wú)窮無(wú)盡越扯越遠(yuǎn)。
我有個(gè)小例子,大家可以按自己的經(jīng)驗(yàn)來(lái)分個(gè)優(yōu)劣。
UserSession
只要涉及用戶登錄的 App,都少不了有個(gè) UserSession 的類,記錄和用戶相關(guān)的一切數(shù)據(jù)和行為,并在用戶登出的時(shí)候做銷毀。UserSession 是一個(gè)一旦創(chuàng)建之后,大部分的業(yè)務(wù)模塊都需要訪問(wèn)的實(shí)例對(duì)象,其他 class 如何訪問(wèn) UserSession,或者說(shuō) UserSession 如何傳遞到各個(gè) class,這里面的做法就多了。
問(wèn)題:ControllerA,ControllerB,ControllerC 都需要訪問(wèn) UserSession 實(shí)例,如何傳遞?
方式一:構(gòu)造傳遞
所有的 Controller 在 init 方法里都傳入 UserSession,之后再內(nèi)部持有一個(gè) strong property,類結(jié)構(gòu)如下圖:
如果使用這種方式,所有需要引用 UserSession 的地方都需要以 init 的方式傳入,包括 Controller 內(nèi)部的 View、Presenter 等對(duì)象,View 可能還有子 View,層層疊疊以樹形結(jié)構(gòu),UserSession 將出現(xiàn)在每一個(gè)相關(guān) Class 的 init 方法之內(nèi)。
方式二:方法參數(shù)傳遞
Controller 本身并不持有 UserSession 的實(shí)例,每個(gè)需要用到 UserSession 的方法以參數(shù)傳入,如下圖:
這種方式相較方式一,UserSession 作為每個(gè)方法的參數(shù)將出現(xiàn)在更多的地方。顯然,不持有 strong property 有他的好處,比如不會(huì)出現(xiàn) Controller 無(wú)法釋放導(dǎo)致 UserSession 也無(wú)法銷毀的情況。UserSession 和 Controller 之間的依賴關(guān)系也更清楚,看 .h 中的方法就一目了然。另外需要測(cè)試某個(gè)方法的時(shí)候,要比較容易,方法的聲明里就有完整的 context。
方式三:內(nèi)部直接持有
Controller 在 .m 文件內(nèi)部通過(guò)另一個(gè) UserMgr 實(shí)例來(lái)統(tǒng)一獲取 UserSession,如下圖:
這種方式在 .h 中看不出 Controller 和 UserSession 的關(guān)系,在 .m 中通過(guò)另一個(gè)類(xxxMgr、xxxFactory、xxxService)來(lái)獲取 UserSession 實(shí)例。好處是 .h 文件干凈一些,但 .m 中可能各處都有獲取 UserSession 的代碼,一旦代碼量多了之后很難理清 Controller 和 UserSession 二者之間的依賴關(guān)系。
以上三種方式我都見(jiàn)到過(guò),不同方式對(duì)代碼的影響也不同,這是個(gè)典型的例子,一個(gè)完整 App 里往往有多個(gè)類似 UserSession 需要被多處引用的對(duì)象,三種方式最后都不會(huì)影響功能的正常實(shí)現(xiàn),但在代碼閱讀維護(hù)上存在一些差異。