1.為什么不使用數(shù)據(jù)對象
問題來源:
- 修改某一領(lǐng)域共享對象或參數(shù)時,可能影響其他領(lǐng)域
- 解決某一問題愈污,如果引入某個充滿各種不同問題領(lǐng)域的函數(shù)集轮傍,實質(zhì)上也就引入了對不同問題領(lǐng)域解決方案的依賴
2.去model化的手段
a.字典流,即使用原生的數(shù)據(jù)流创夜,通過NSDictionary方式傳遞
b.reformer(本文重點)
- 問題1:使用哪種交互模式來跟業(yè)務(wù)層做對接?
- 問題2:是否有必要將API返回的數(shù)據(jù)封裝成對象然后再交付給業(yè)務(wù)層杭跪?
- 問題3:使用集約化調(diào)用方式還是離散型調(diào)用方式去調(diào)用API?
回答1:使用哪種交互模式來跟業(yè)務(wù)層做對接
1.1 以什么方式將數(shù)據(jù)交付給業(yè)務(wù)層?
大多數(shù)App在網(wǎng)絡(luò)層采用的方式:Delegate涧尿、Notification系奉、Block,建議使用Delegate姑廉,理由如下:
i.盡可能減少跨層數(shù)據(jù)交流的可能缺亮,限制耦合
ii.統(tǒng)一回調(diào),便于調(diào)試和維護(hù)
iii.在跟業(yè)務(wù)層對接的部分只采用一種對接手段庄蹋,限制靈活性瞬内,來交換應(yīng)用的可維護(hù)性
** 什么是跨層數(shù)據(jù)交流? **
--- 就是某一層(或模塊)跟另外的與之沒有直接對接關(guān)系的層(或模塊)產(chǎn)生了數(shù)據(jù)交換限书。
** 為什么這種情況不好虫蝶? **
--- 這會導(dǎo)致代碼混亂,破壞模塊的封裝性倦西。
** 我們做分層架構(gòu)的目的 **
--- 其中之一就在于** 下層對上層有一次抽象能真,讓上層可以不必關(guān)心下層細(xì)節(jié)而執(zhí)行自己的業(yè)務(wù) **。如果下層細(xì)節(jié)被跨層暴露扰柠,一方面你很容易因此失去鄰層對這個暴露細(xì)節(jié)的保護(hù)粉铐;另一方面,你又不可能不去處理這個細(xì)節(jié)卤档,所以處理細(xì)節(jié)的相關(guān)代碼就會散落各地蝙泼,最終難以維護(hù)
** Notification **
--- 使用Notification給跨層數(shù)據(jù)交流開了一道口子,相關(guān)處理的代碼不能保證都在唯一的地方劝枣。不過汤踏,在屬于它的問題領(lǐng)域中,這也是一種非常好的解決方案
** Block **
--- 很難追蹤舔腾,難以維護(hù)溪胶。block會延長相關(guān)對象的生命周期。block在離散型場景下不符合使用的規(guī)范稳诚。
當(dāng)回調(diào)之后要做的任務(wù)在每次回調(diào)時都是一致的情況下哗脖,選擇delegate,在回調(diào)之后要做的任務(wù)在每次回調(diào)時無法保證一致扳还,選擇block才避。在** 離散型調(diào)用的場景 下,每一次回調(diào)都是能夠保證任務(wù)一致的氨距,因此適用delegate桑逝。 蘋果原生的網(wǎng)絡(luò)調(diào)用 采用delegate,因為蘋果是基于離散模型去設(shè)計網(wǎng)絡(luò)調(diào)用的衔蹲。在 集約型調(diào)用的場景 下,使用block是合理的,因為每次請求的類型都不一樣舆驶,那么自然回調(diào)要做的任務(wù)也都會不一樣橱健。 AFNetworking 就是屬于集約型調(diào)用,因此它采用了block來做回調(diào)沙廉。
在網(wǎng)絡(luò)請求和網(wǎng)絡(luò)層接受請求的地方時拘荡,使用Block沒問題撬陵。但是在獲得數(shù)據(jù)交給業(yè)務(wù)方時,最好還是通過Delegate去通知到業(yè)務(wù)方巨税。我們實際編碼時也會意識到盡可能讓 Block的回調(diào)著陸點統(tǒng)一 **,所以選擇在block里面寫個一句話的方法接收參數(shù)草添,然后做轉(zhuǎn)發(fā),然后就可以把這個方法放在其他地方抄淑,這實質(zhì)上跟使用Delegate的手段沒有什么區(qū)別驰后,只是繞了一下,不過還是沒有解決統(tǒng)一回調(diào)方法的問題灶芝,因為block里面寫的方法名字可能在不同的ViewController對象中都會不一樣,所以颤专,建議的寫法如下:
[AFNetworkingAPI callApiWithParam:self.param successed:^(Response *response){
if ([self.delegate respondsToSelector:@selector(successWithResponse:)]) {
[self.delegate successedWithResponse:response];
}
} failed:^(Request *request, NSError *error){
if ([self.delegate respondsToSelector:@selector(failedWithResponse:)]) {
[self failedWithRequest:request error:error];
}
}];
1.1小結(jié):以什么方式將數(shù)據(jù)交付給業(yè)務(wù)層钠乏?
盡可能通過Delegate的回調(diào)方式交付數(shù)據(jù),這樣可以避免不必要的跨層訪問簇捍。當(dāng)出現(xiàn)跨層訪問的需求時(比如信號類型切換),通過Notification的方式交付數(shù)據(jù)暑塑。正常情況下應(yīng)該是避免使用Block的
1.2 交付什么樣的數(shù)據(jù)給業(yè)務(wù)層锅必?
大部分的做法是:將拿到的JSON數(shù)據(jù)惕艳,轉(zhuǎn)變成對應(yīng)的對象模型驹愚,這么做有如下成本:
1.數(shù)組內(nèi)容轉(zhuǎn)化成本高
2.存在需要2次轉(zhuǎn)化的數(shù)據(jù)
3.只有API返回的數(shù)據(jù)高度標(biāo)準(zhǔn)化時,生成的Model的可復(fù)用性才高
4.調(diào)試時谁鳍,Model的展示不如NSDictionary/NSArray直觀
5.同一個API的數(shù)據(jù)被不同的View展示劫瞳,難以控制數(shù)據(jù)轉(zhuǎn)化的代碼,有可能散落在多個地方
1.2小結(jié):交付什么樣的數(shù)據(jù)給業(yè)務(wù)層
對于業(yè)務(wù)層而言志于,由Controller根據(jù)View和APIManager之間的關(guān)系,選擇合適的reformer將View可以直接使用的數(shù)據(jù)(甚至reformer可以用來直接生成view)轉(zhuǎn)化好之后交付給View蕊退。對于網(wǎng)絡(luò)層而言憔恳,只需要保持住原始數(shù)據(jù)即可,不需要主動轉(zhuǎn)化成數(shù)據(jù)原型钥组。然后數(shù)據(jù)采用NSDictionary加Const字符串key來表征,避免了使用對象來表征帶來的遷移困難点把,同時不失去可讀性