前言
2018年底,對于已經(jīng)從事軟件開發(fā)工作了4年多的我劝堪,經(jīng)歷從輾轉(zhuǎn)深圳、流浪貴陽的顛簸幅聘,由于多年的開發(fā)經(jīng)驗(yàn)凡纳,自我審視的時(shí)候發(fā)現(xiàn)自己業(yè)務(wù)能力不錯(cuò)帝蒿、項(xiàng)目經(jīng)驗(yàn)豐富,但對計(jì)算機(jī)底層缺乏較深的認(rèn)識(shí)巷怜,對設(shè)計(jì)模式也沒有深刻的理解葛超。當(dāng)然延塑,這是我接下來一段時(shí)間工作的重點(diǎn)绣张。
為什么說這么多廢話关带,因?yàn)橹拔也]有打算在本文中探討太專業(yè)的東西侥涵,而本文目標(biāo)也是面向像我一樣深處迷茫探索中的小白,主要從宏觀上聊聊工程結(jié)構(gòu)宋雏、從微觀上聊聊類的設(shè)計(jì)。
本文構(gòu)思基礎(chǔ)
之前在公司開發(fā)遇到幾個(gè)問題
1.項(xiàng)目太大磨总,運(yùn)行調(diào)試太慢嗦明,感覺降低了開發(fā)效率
2.項(xiàng)目由于底層庫的原因不能模擬器調(diào)試蚪燕,只能真機(jī)娶牌,進(jìn)一步降低效率
3.工程文件結(jié)構(gòu)復(fù)雜,開發(fā)人員較多诗良,相關(guān)模塊分離不明顯,難以尋找
4.類似滴滴打車這樣的項(xiàng)目鲁驶,需要開發(fā)多個(gè)客戶端,但功能、網(wǎng)絡(luò)接口等基本相同壹罚,如果使用多個(gè)工程導(dǎo)致大量重復(fù)代碼葛作,將來也不容易同步維護(hù)相同邏輯的代碼
探索思路
1.組件化探索猖凛、插件化設(shè)計(jì)思路
2.多target模塊設(shè)計(jì)思路赂蠢,新建target包裝較復(fù)雜的模塊,一方面可以分離業(yè)務(wù)邏輯辨泳,另一方面也可以使得單個(gè)模塊運(yùn)行速度更快、解決不能真機(jī)調(diào)試問題
新問題
1.公共模塊內(nèi)部引用了其它無關(guān)模塊的邏輯菠红,當(dāng)分離出target以后發(fā)現(xiàn)target并不單純第岖,還是需要引入編譯大量無關(guān)邏輯的代碼试溯,為達(dá)到編譯效率最大化
2.如果需要開發(fā)一個(gè)項(xiàng)目多個(gè)客戶端蔑滓,達(dá)不到邏輯清晰可辨,還是會(huì)帶來維護(hù)上的問題
最終
1.花了大量時(shí)間重構(gòu)了公共模塊代碼键袱,分類模塊之間業(yè)務(wù)邏輯
2.基本類似的功能業(yè)務(wù)遷移重構(gòu),達(dá)到解耦復(fù)用目的
3.只做了項(xiàng)目中一小部分的工作摹闽,難以達(dá)到理想中的效果,不過:一直在路上
思考:不忘初心
- 宏觀上最初的工程架構(gòu)
- 微觀上具體到每個(gè)類的設(shè)計(jì)
- 中觀上建立自己的公共代碼倉庫
關(guān)于工程結(jié)構(gòu)
在開發(fā)新項(xiàng)目前付鹿,你首先應(yīng)該有一個(gè)清晰的工程結(jié)構(gòu)澜汤,無論做什么事情之前我們都應(yīng)該有一段長長的思考舵匾,多對自己提一些疑問俊抵,多像自己談?wù)劇盀槭裁矗俊薄?/strong>
iOS開發(fā)工程目錄結(jié)構(gòu)
在我們熟知的設(shè)計(jì)模式中纽匙,以MVC名頭最響,MVVM更像是另辟蹊徑或者說別出機(jī)杼烛缔,或許有人會(huì)說這是標(biāo)新立異馏段、故意顯擺践瓷,關(guān)于孰優(yōu)孰劣再次不做討論院喜,開發(fā)上的各種思路見仁見智,我個(gè)人更推薦MVVM晕翠。
根據(jù)個(gè)人習(xí)慣有所不同砍濒,有些人喜歡整個(gè)項(xiàng)目結(jié)構(gòu)中就是一個(gè)巨型MVC或者M(jìn)VVM,即外層結(jié)構(gòu)+內(nèi)部模塊硫麻,然后再在“Models/”或者“Views/”、“Controllers/”等目錄下分模塊拿愧,如GitHub優(yōu)秀APP源碼Coding-iOS客戶端杠河。
而有些人喜歡這樣分浇辜,外層模塊+內(nèi)部結(jié)構(gòu)券敌,如下圖方式
具體宏觀上用什么目錄結(jié)構(gòu)見仁見智柳洋,記住沒有最好只有更好待诅,對我來說我推薦第一種,可能是習(xí)慣亦或是對大神的仰慕熊镣。
不管什么方式,只要在自己心目中設(shè)計(jì)的時(shí)候按照清晰的MVC或者M(jìn)VVM設(shè)計(jì)轧钓,就非常容易理清邏輯序厉,但對于一個(gè)工程來說毕箍,微觀上的架構(gòu)可能才是最重要的,因?yàn)槲覀冊诨◣滋鞎r(shí)間建立好工程后道盏,接下來的所有日志都主要集中在微觀邏輯架構(gòu)的開發(fā)維護(hù)上而柑,因此我說微觀上的架構(gòu)更重要荷逞,而最初的架構(gòu)設(shè)計(jì)確實(shí)無與倫比的媒咳,將決定了項(xiàng)目未來的代碼如何發(fā)展、是否易于擴(kuò)展涩澡、開發(fā)和維護(hù)等。
關(guān)于類的設(shè)計(jì)
我們常說到低耦合坠敷、高內(nèi)聚思想妙同,基本任何開發(fā)人員都知道這個(gè)概念膝迎,但在設(shè)計(jì)上卻鮮有人能熟練駕馭粥帚。我們總在不知不覺中被方便的思想左右,不愿意去寫接口協(xié)議芒涡、不愿意去做回調(diào)hook處理,這都是通病,以下通過實(shí)例談?wù)効捶?/strong>
1.設(shè)計(jì)一個(gè)通用類:圖片展示器 ImageBrowser
// ImageBrowser應(yīng)該向外提供如下接口
- images/imageURLs接收方法
- show方法(打開)
- close方法(關(guān)閉)
- block/delegate回調(diào)
// 注意事項(xiàng)
// 1.該類不應(yīng)該使用項(xiàng)目中定義的一些Define费尽、Models、Views等
// 2.該類不應(yīng)該引用項(xiàng)目中某些類的頭文件旱幼,不應(yīng)該和項(xiàng)目中某些類的邏輯相關(guān)聯(lián)乎串,只能向外提供訪問接口
// 3.該類的總體思路應(yīng)該是單向的速警,即項(xiàng)目中類可以訪問它叹誉,而它不能直接訪問項(xiàng)目中的類
// 4.設(shè)計(jì)為插件式模塊,引入和抽離只需少量代碼闷旧,大量初始化工作應(yīng)在內(nèi)部完成,向外提供的應(yīng)該是非常簡潔的接口
2.第三方庫橋接文件忙灼,我們在項(xiàng)目中接入第三方庫的時(shí)候一般不會(huì)直接使用匠襟,應(yīng)該是簡歷橋接文件去和第三方庫對接该园,將來如果第三方庫更換也不用變動(dòng)項(xiàng)目代碼酸舍,只需維護(hù)橋接文件即可。如設(shè)計(jì)一個(gè)AFNetworking的管理類
// 應(yīng)該向外提供如下接口
- get:(參數(shù)) block:(回調(diào)結(jié)果)
- post:(參數(shù)) block:(回調(diào)結(jié)果)
- upload:(參數(shù)) progressBlock:(回調(diào)進(jìn)度) block:(回調(diào)結(jié)果)
...
// 注意事項(xiàng)
// 1.該類只與AFNetworking關(guān)聯(lián)啃勉,不應(yīng)該關(guān)聯(lián)項(xiàng)目中的Define、Models双妨、Views等
// 2.遵循單向訪問邏輯原則
// 3.遵循接口簡介原則
3.設(shè)計(jì)UITableViewCell
// 1.向外暴露需要變動(dòng)展示數(shù)據(jù)的property
@property (nonatomic, weak) UILabel *titleLabel;
@property (nonatomic, weak) UIImageView *imageView;
...
// 向外提供hook接口
- block/delegate回調(diào)
// 注意事項(xiàng)
// 1.該類不應(yīng)該引直接引用Model淮阐,不應(yīng)該在內(nèi)部處理交互事件刁品,應(yīng)hook到controller處理
// 2.該類若必須處理大量內(nèi)部邏輯泣特,考慮綁定viewModel或者為其添加分類Category
// 3.該類不應(yīng)該引用其他模塊的頭文件
4.此外設(shè)計(jì)Tools、Category状您、Helper等工具類的時(shí)候也盡量保持相互間的獨(dú)立性
好處
1.不同模塊角色明晰,代碼均衡分布于這些模塊上
2.由第1點(diǎn)帶來的可測試性
3.易用性兜挨,維護(hù)成本低
4....