NotificationCenter 協(xié)議

讓觀察者模式變得更美好

OSX 已經(jīng)有至少 17 年的歷史垮庐,而NotificationCenter在其第一次版本發(fā)布就已經(jīng)存在,并且一直是蘋果開發(fā)者常用的工具。對于不了解的人來說,NotificationCenter 是基于觀察者模式的概念卷胯,也是軟件設(shè)計模式中行為型模式的一部分。

觀察者模式

觀察者模式由Gang of Four在 90 年代中期提出并一直存在威酒,是一種比較容易理解的設(shè)計模式窑睁。首先,會存在一個被稱之為觀察目標(biāo)的對象葵孤;這個對象維護一個包含觀察者的列表担钮,并將狀態(tài)的變化通知給這些觀察者。

舉個真實的例子佛呻。你所在的城市有一家繁忙的咖啡店裳朋。不少顧客在排隊買咖啡,咖啡師會詢問顧客的姓名吓著,并將其寫在杯子上鲤嫡,以便分清楚咖啡是誰點的;然后讓顧客禮貌地等待其名字被叫绑莺。每制作完一杯咖啡暖眼,咖啡師會叫出杯子上所寫的名字,從而讓顧客愉快地取到自己所點的咖啡纺裁。

在這種情況下诫肠,咖啡師是觀察目標(biāo)司澎,購買咖啡的顧客是觀察者,而咖啡是狀態(tài)的變化栋豫,因為咖啡從一個空杯變成了滿滿一杯含咖啡因的美味挤安。

NotificationCenter的問題

對于寫代碼的我們,觀察者模式毫無疑問是一種有很多用途的偉大模式丧鸯。但同時不得不承認蛤铜,我從來不是它的狂熱粉絲,并非因為缺乏一些好的理由:

保證觀察對象的一致性

如果一個項目中沒有強制性的標(biāo)準丛肢,那么實現(xiàn)和向觀察者發(fā)送通知的方式可能就會多種多樣围肥。例如混亂的通知名稱:

classBarista{

letnotification ="coffeeMadeNotification"

}

classTrainee{

letcoffeeMadeNotificationName ="Coffee Made"

}

避免通知名稱沖突

如果開發(fā)者隨意給通知起名,那么兩個不同的觀察對象則可能擁有相同的通知名蜂怎,于是無論這兩者誰發(fā)出一個采用此名字的通知穆刻,錯誤的觀察者便可能會收到此通知。

假設(shè)咖啡店里有兩個咖啡師杠步,如果每個咖啡師都用相同的通知名氢伟,顧客便會收到毫無意義的通知,甚至更糟的是篮愉,會收到一杯含有大豆印度茶并且不含咖啡因的香草拿鐵而不是一杯拿鐵咖啡腐芍。

classBarista{

staticletcoffeeMadeNotification ="coffeeMadeNotification"

}

classTrainee:Barista{ }

...

NotificationCenter.default.

.postNotificationName(Trainee.coffeeMadeNotification)

使用字符串作為名稱的通知

我會避免使用字符串類型的通知差导,你也應(yīng)該如此试躏,因為這樣只會產(chǎn)出容易出錯的代碼。永遠不要相信人們避免拼寫錯誤或在沒有自動補全功能環(huán)境下編程的能力设褐。

NSNotificationCenter.defaultCenter()

.postNotificationName("coffeeMadNotfication")

替代方案

更多的時候颠蕴,我會盡可能使用代理模式來代替觀察者模式。代理模式與觀察者模式非常相似助析,但并不是一對多的關(guān)系犀被,代理模式是一對一的關(guān)系。雖然代理模式也有自己的一些問題和限制外冀,但它避免了我上面列出的問題寡键,所以在我看來這種模式是更可靠的選擇。不過今天并不會深入探討這些問題雪隧。

通知協(xié)議

protocolNotifier{ }

我們可以設(shè)計一個協(xié)議來解決上面列出的所有問題西轩,于是接下來挨個研究下這些問題,然后實現(xiàn)一個更 Swift 化的脑沿、有統(tǒng)一變化的NSNotificationCenter實現(xiàn)藕畔。

保證觀察對象的一致性

協(xié)議非常有用,因為想要遵守某個協(xié)議庄拇,就必須強制符合其規(guī)范注服。所以針對于這個協(xié)議韭邓,我們將給它設(shè)置一個關(guān)聯(lián)類型:

protocolNotifier{

associatedTypeNotification:RawRepresentable

}

從現(xiàn)在開始,如果在項目中的類或結(jié)構(gòu)體想要發(fā)布通知溶弟,那就應(yīng)該遵守Notifier協(xié)議女淑,并提供遵守RawRepresentable協(xié)議的關(guān)聯(lián)類型。

classBarista:Notifier{

enumNotification:String{

casemakingCoffee

casecoffeeMade

}

}

在 Swift 中辜御,由于枚舉也可以遵守RawRepresentable協(xié)議诗力,所以可以使用一個String類型的枚舉,并命名相應(yīng)的通知我抠。

letcoffeeMade =Barista.Notification.coffeeMade.rawValue

NSNotificationCenter.defaultCenter()

.postNotificationName(coffeeMade)

避免通知名稱沖突

同樣苇本,枚舉在這方面也起了很大作用,因為它可以讓我們避免重復(fù)定義菜拓。如果我們創(chuàng)建了多個makeCoffee的枚舉瓣窄,編譯器將提示錯誤。然而纳鼎,這并不能解決具有不同類或結(jié)構(gòu)但具有相同枚舉名稱的問題。

letbaristaNotification =Barista.Notification.coffeeMade.rawValue

lettraineeNotification =Trainee.Notification.coffeeMade.rawValue

// baristaNotification: coffeeMade

// traineeNotification: coffeeMade

如上所見贱鄙,需要為這些通知創(chuàng)建一個唯一的命名空間劝贸,來保證通知名稱之間沒有任何沖突逗宁。使用對應(yīng)的對象名稱是一種很好的解決方案,因為編譯器不允許類或結(jié)構(gòu)體具有相同的名稱瞎颗。

letbaristaNotification =

"\(Barista).\(Barista.Notification.coffeeMade.rawValue)"

lettraineeNotification =

"\(Trainee).\(Trainee.Notification.coffeeMade.rawValue)"

// baristaNotification: Barista.coffeeMade

// traineeNotification: Trainee.coffeeMade

到目前為止都很順利,但是現(xiàn)在我們的實現(xiàn)方案到了一個左右為難的境地哼拔。一方面引有,我們解決了命名空間重復(fù)的問題,但另一方面我們的代碼看起來像是一坨垃圾倦逐。的確譬正,雖然已經(jīng)實現(xiàn)了一些統(tǒng)一性,但是如果沒有任何保護措施來防止我們自己和協(xié)作的開發(fā)人員忘記添加命名空間檬姥,那么這個方案是毫無意義的吧曾我?

通知實現(xiàn)

對你來說幸運的是,我自己已經(jīng)考慮到這一點穿铆,并避免了上述的糟糕情況您单。我們將進一步擴展我們的協(xié)議,并在 NSNotificationCenter 功能調(diào)用方面添加一些很友好的符合Swift API 指南的荞雏、特定類型的語法糖虐秦。

通知名稱

Barista.coffeeMade

我們通常希望使用自己的通知命名空間和名稱平酿,因此會創(chuàng)建一個以通知枚舉為參數(shù)的函數(shù),這個函數(shù)會在我們發(fā)出通知和移除觀察者時返回安全的通知名稱悦陋。這個函數(shù)也是私有的蜈彼,因為我們并不希望外部的代碼訪問此功能,而是由自己和同事強制地遵守通知協(xié)議俺驶,從而具備了本來實現(xiàn)不了的優(yōu)點幸逆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市暮现,隨后出現(xiàn)的幾起案子还绘,更是在濱河造成了極大的恐慌,老刑警劉巖栖袋,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拍顷,死亡現(xiàn)場離奇詭異,居然都是意外死亡塘幅,警方通過查閱死者的電腦和手機昔案,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來电媳,“玉大人踏揣,你說我怎么就攤上這事∝遗遥” “怎么了捞稿?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钝尸。 經(jīng)常有香客問我括享,道長,這世上最難降的妖魔是什么珍促? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮剩愧,結(jié)果婚禮上猪叙,老公的妹妹穿的比我還像新娘。我一直安慰自己仁卷,他們只是感情好穴翩,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锦积,像睡著了一般。 火紅的嫁衣襯著肌膚如雪背蟆。 梳的紋絲不亂的頭發(fā)上鉴分,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天志珍,我揣著相機與錄音垛叨,去河邊找鬼。 笑死嗽元,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的载慈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼办铡,長吁一口氣:“原來是場噩夢啊……” “哼琳要!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起童叠,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤课幕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后杜秸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡撬碟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年呢蛤,在試婚紗的時候發(fā)現(xiàn)自己被綠了棍郎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡励翼,死狀恐怖蜈敢,靈堂內(nèi)的尸體忽然破棺而出扶认,到底是詐尸還是另有隱情,我是刑警寧澤辐宾,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布膨蛮,位于F島的核電站,受9級特大地震影響敞葛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜持偏,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一氨肌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怎囚,春花似錦、人聲如沸恳守。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颗圣。三九已至,卻和暖如春在岂,著一層夾襖步出監(jiān)牢的瞬間蛮寂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工及老, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骄恶。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像僧鲁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寞秃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容