今年剛開始的時(shí)候就想了很多汉柒,但是拖拖拉拉的到了五月才進(jìn)行設(shè)想的第一步(嗯,沒錯(cuò)…是今年目標(biāo)的第一階段…)
入職新公司一年多了,在需求的包圍下業(yè)務(wù)代碼咔咔的寫了很多赠堵,寫著寫著..發(fā)現(xiàn)不對(duì)啊,這個(gè)還有那個(gè)我好想在哪見過一樣的…這種搭訕的橋段讓我決定先總結(jié)總結(jié)當(dāng)前的的一些問題法褥,然后學(xué)習(xí)如何重構(gòu)茫叭。
問題歸納
所有人在嘗試重構(gòu)前都會(huì)遇到的幾個(gè)大boss:
① 重復(fù)代碼過多
舉個(gè)簡(jiǎn)單的例子: 我們光一個(gè)輪播圖樣式就已經(jīng)出現(xiàn)了3、4個(gè)以banner為后綴的文件半等。
② 結(jié)構(gòu)定義不夠規(guī)范
從整個(gè)頁面結(jié)構(gòu)這么大的角度而言就已經(jīng)出現(xiàn)了好幾套揍愁,改bug看別人寫的結(jié)構(gòu)還得想一想...
③ 新舊兼容問題
在業(yè)務(wù)發(fā)展一定階段的時(shí)候,一定會(huì)遇到兼容的問題杀饵,新的結(jié)構(gòu)擺在這里莽囤,但是為了兼容舊結(jié)構(gòu)居然…無視新的結(jié)構(gòu),不采用一層抽象替換凹髓,而是直接使用舊的結(jié)構(gòu)
總而言之烁登,即便是業(yè)務(wù)代碼也隨著歲月積累了越來越多的問題,而且現(xiàn)在還在繼續(xù)...所以一邊學(xué)習(xí)一邊決定走上重構(gòu)的道路蔚舀。
重構(gòu)第一階段
以擁有3饵沧、4個(gè)以banner為后綴文件的輪播圖為例:
當(dāng)前業(yè)務(wù)同時(shí)在使用BannerView和BannerCell兩種輪播圖控件類型,而不同的業(yè)務(wù)在添加新功能時(shí)并不是在現(xiàn)有代碼的基礎(chǔ)上進(jìn)行修改赌躺,反而是在不斷的復(fù)制新的控件以滿足新需求狼牺。
第一步: 創(chuàng)建抽象層
將通用部分進(jìn)行抽象,每一個(gè)業(yè)務(wù)都只需要考慮不同的部分礼患,減少了代碼的重復(fù)性是钥,也讓整體的結(jié)構(gòu)變得更加的清晰。
第二步:對(duì)象的多態(tài)性
以banner的size進(jìn)行考慮缅叠,目前是直接使用判斷語句來調(diào)整layout布局:
如果是A悄泥,就采用A關(guān)聯(lián)的size,
如果是B肤粱,就采用B關(guān)聯(lián)的size
.....
判斷條件是最簡(jiǎn)單直接表達(dá)出類多態(tài)的效果弹囚,但是這里面涉及到我一直以來的困惑:
什么時(shí)候用判斷條件?什么時(shí)候用對(duì)象的多態(tài)性领曼?
就目前可以給的建議:
如果對(duì)象間差異性很大鸥鹉,也就是非通用性的部分已經(jīng)到了新寫一個(gè)對(duì)象的程度蛮穿,就直接用多態(tài)性來做。
因?yàn)闃I(yè)務(wù)不只是在對(duì)size有差異毁渗,所以將判斷語句移除替換成各個(gè)業(yè)務(wù)對(duì)象自己進(jìn)行處理践磅。
第三步:細(xì)節(jié)把控
① 提煉函數(shù)
如果在定義一個(gè)函數(shù)名時(shí),左看看右看看無法完全覆蓋當(dāng)前函數(shù)的內(nèi)容灸异,那么就說明是時(shí)候提煉多個(gè)函數(shù)了
② 命名格式
首先府适,對(duì)于類中的私有函數(shù)可以在函數(shù)名前加一些標(biāo)識(shí)符,如“_”或”p”
- (void)initializeView {
[super initializeView];
self.clipsToBounds = YES;
[self __initialWithScrollImageView];
[self __initialWithNotification];
}
其次绎狭,對(duì)于一些參數(shù)或函數(shù)的命名不是越長(zhǎng)越好细溅,而是能明確的說明該參數(shù)在使用范圍內(nèi)是干啥的就行。
舉個(gè)例子:
- (NSArray<NSString *> *)imageArray{}
乍看之下儡嘶,這個(gè)方法…應(yīng)該是想要得到所有的圖片信息喇聊,返回值的數(shù)組中又是字符串..一番腦部小活動(dòng)
- (NSArray <NSString *> *)imageUrls{}
但是,改成這樣就很直接...拿的就是圖片的Url,猜都不用猜蹦狂。
③ Delegate和block
在一些小的控件中都會(huì)同時(shí)存在Delegate和block誓篱,是Delegate不能滿足你還是block不夠強(qiáng)大?
如果只是類中只會(huì)需要處理少量的外傳以及參數(shù)很少的話凯楔,會(huì)優(yōu)先考慮block窜骄;相反情況下則會(huì)以delegate為主,而delegate內(nèi)部的方法命名也常是我很焦慮的一點(diǎn):
@protocol MallIndexBannerScrollDelegate <NSObject>
@optional
- (void)bannerView:(MallBaseBannerView *)bannerView willDisplayCell:(UICollectionViewCell *)cell indexPath:(NSIndexPath *)indexPath;
- (void)bannerView:(MallBaseBannerView *)bannerView didSelectItemAtIndex:(NSInteger)index;
@end
大部分人會(huì)覺得應(yīng)該去模仿官方的代理回調(diào)方法格式摆屯,道理是沒有錯(cuò)邻遏,但是首先還是以自己的風(fēng)格為主,其次減少無用參數(shù)的外傳
④ 方法的迭代
功能的重構(gòu)是不應(yīng)該影響業(yè)務(wù)的使用虐骑,但經(jīng)常會(huì)發(fā)生刪除或者調(diào)整了某個(gè)方法准验,在檢查沒有完全覆蓋的情況下可能導(dǎo)致崩潰或者無法點(diǎn)擊等問題。
對(duì)于通用控件而言廷没,可以使用deprecated聲明
+ (NSArray *)allHUDsForView:(UIView *)view __attribute__((deprecated("Store references when using more than one HUD per view.")));
但是對(duì)于業(yè)務(wù)線內(nèi)部使用的控件糊饱,除了及時(shí)檢查,各個(gè)業(yè)務(wù)線中共享控件使用文檔之外颠黎,好像也無法要求再多另锋。
總結(jié)
剛開始看關(guān)于重構(gòu)的一些資料和書,先拿輪播圖小小的試水狭归,還有一些類似靈活性夭坪、新舊邏輯兼容問題等慢慢來,動(dòng)手前考慮好架構(gòu)大方向过椎。