說(shuō)完觀察者和發(fā)布訂閱模式的區(qū)別,面試官不留我吃飯了
本文轉(zhuǎn)載自微信公眾號(hào)「愛(ài)笑的架構(gòu)師」,作者雷架。轉(zhuǎn)載本文請(qǐng)聯(lián)系愛(ài)笑的架構(gòu)師公眾號(hào)。
來(lái)到心儀已久的公司面試,剛推開(kāi)門(mén)還沒(méi)等我說(shuō)話HR 小姐姐就主動(dòng)問(wèn)我:你是來(lái)參加面試的吧?
我心想不對(duì)啊:難道是因?yàn)槲议L(zhǎng)的帥,小姐姐一眼就看出來(lái)我將來(lái)是這棟樓的主人,所以才主動(dòng)跟我打招呼。
我昂起頭,略微點(diǎn)點(diǎn)頭:是的。
HR小姐姐:面試官馬上就過(guò)來(lái),我先帶你去會(huì)議室。
在去會(huì)議室的路上,我發(fā)現(xiàn)大家脖子上都帶著亮閃閃的工牌,我下意識(shí)的看了看我的脖子上,除了昨天沒(méi)有洗澡留下來(lái)的一點(diǎn)汗?jié)n啥也沒(méi)有。
原來(lái)是因?yàn)槲覜](méi)帶工牌才認(rèn)出我的,頓時(shí)我的臉滾燙滾燙的,我承認(rèn)剛才我有點(diǎn)自戀了。
HR小姐姐:怎么了,你臉怎么紅通通的,是不舒服嗎?
我摸了摸臉:沒(méi)有沒(méi)有,面試有點(diǎn)緊張,害。
來(lái)到會(huì)議室,HR 小姐姐給我遞過(guò)一杯水:面試官臨時(shí)有個(gè)會(huì),你稍微等一會(huì)。
我:好的。
我心里咕嚕:怎么突然有個(gè)會(huì),會(huì)不會(huì)是因?yàn)榭戳宋业暮?jiǎn)歷覺(jué)得我菜,故意找了一個(gè)借口,待會(huì)肯定讓 HR 過(guò)來(lái)說(shuō)面試太忙今天不面了。
果不其然,門(mén)開(kāi)了,一位頭發(fā)油油的滿臉是痘的中年大叔向我走來(lái)。
我心想:這不會(huì)就是傳說(shuō)中的架構(gòu)師吧??磥?lái)還是很看重我啊,第一面就派一個(gè)架構(gòu)師來(lái)面我,我得好好表現(xiàn)一下。
架構(gòu)師:你就是xxx 吧,剛才有個(gè)會(huì)議我來(lái)晚了,我們開(kāi)始面試吧,一分鐘簡(jiǎn)單介紹一下自己。
果然沒(méi)有猜錯(cuò),給我一分鐘介紹,幸虧之前是按照一分鐘準(zhǔn)備的,我要開(kāi)始背了。
我張嘴一笑,露出自信的大牙:尊敬的架構(gòu)師你好,我是 xxx,之前在上一家公司擔(dān)任……
架構(gòu)師點(diǎn)點(diǎn)頭:很好。我看你簡(jiǎn)歷上寫(xiě)了很多技能,你挑一個(gè)你最熟悉的。
我有點(diǎn)凌亂了:架構(gòu)師怎么不按套路出牌,應(yīng)該會(huì)問(wèn)我 HashMap 的源碼,Java 鎖的機(jī)制等。我想了想我比較熟悉的:Java 集合類(lèi)、JVM、多線程、spring 全家桶,我如果說(shuō)這些肯定會(huì)被架構(gòu)師鄙視,差點(diǎn)忘了我還有一個(gè)殺手锏:設(shè)計(jì)模式。
我拍了拍胸脯:架構(gòu)師你好,我之前參與項(xiàng)目重構(gòu)用到了很多設(shè)計(jì)模式,要不你問(wèn)我設(shè)計(jì)模式的東西吧。
架構(gòu)師:那你說(shuō)說(shuō)觀察者模式和發(fā)布訂閱模式的區(qū)別?
我腦海立刻閃現(xiàn)《Head First設(shè)計(jì)模式》里面講的:Publishers + Subscribers = Observer Pattern,問(wèn)這么簡(jiǎn)單的問(wèn)題難道是看不起我嗎。
我內(nèi)心無(wú)比激動(dòng),嘴角露出勝利者的微笑:親愛(ài)的架構(gòu)師,我之前看過(guò)一本書(shū)《Head First 設(shè)計(jì)模式》,這里面講的觀察者模式和發(fā)布訂閱模式是等同關(guān)系的,它們是一回事。
架構(gòu)師也笑了:不,它們不一樣。
此刻我慌了,雙手有點(diǎn)輕微顫抖,我哪里錯(cuò)了,它們明明是相等的。
架構(gòu)師:我待會(huì)還有個(gè)會(huì),要不今天的面試先到這里,你回家等消息吧。
回家后我心不甘,決定要把觀察者模式和發(fā)布訂閱模式搞清楚,通過(guò)一頓谷歌后我寫(xiě)了下面這些筆記:
觀察者模式
觀察者模式一般有觀察者和被觀察者。舉個(gè)例子:大家在學(xué)校上自習(xí)的時(shí)候,等老師走了有些人會(huì)玩手機(jī)、吃零食、交頭接耳找隔壁妹妹聊天,但是被老師發(fā)現(xiàn)可就不好了,所以大家想了一個(gè)招,讓坐在最后排的同學(xué)幫忙“放風(fēng)”,老師一來(lái)就給大家一個(gè)手勢(shì)通知大家,大家就繼續(xù)裝好好學(xué)生(哈嘿)。
這其實(shí)就是一個(gè)典型的觀察者模式,“放風(fēng)”的同學(xué)是被觀察者,玩手機(jī)、吃零食的同學(xué)是觀察者,大家都在觀察“放風(fēng)”同學(xué)的手勢(shì),一旦老師來(lái)了,被觀察者就會(huì)通知大家。
好了,讓我們看看 UML 建模是如何定義的。
觀察者模式定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。
UML結(jié)構(gòu)圖如下:
Subject類(lèi)是主題,它把所有對(duì)觀察者對(duì)象的引用文件存在了一個(gè)集合里,每個(gè)主題都可以有任何數(shù)量的觀察者。它是一個(gè)抽象主題,提供了一個(gè)可以增加和刪除觀察者對(duì)象的接口。
Observer類(lèi)是抽象觀察者,為所有的具體觀察者定義一個(gè)接口,在得到主題的通知時(shí)更新自己。
ConcreteSubject類(lèi)是具體主題,將有關(guān)狀態(tài)存入具體觀察者對(duì)象,在具體主題內(nèi)部狀態(tài)改變時(shí),給所有登記過(guò)的觀察者發(fā)出通知。
ConcreteObserver是具體觀察者,實(shí)現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)相協(xié)同。
發(fā)布訂閱模式
舉個(gè)生活中的例子,比如我們想要訂閱一份國(guó)家地理雜志,一般需要我們先向郵局申請(qǐng)(付錢(qián)),告訴郵局我要訂閱這份雜志,苦等數(shù)日雜志終于印刷好了,這個(gè)時(shí)候我們不會(huì)直接跑到印刷廠里去,而是等印刷廠將雜志送給郵局,然后郵局才會(huì)慢吞吞地將雜志送到家(推模式),如果你實(shí)在等不及了跑到郵局直接取雜志,恭喜你學(xué)會(huì)了“拉模式”。
用專(zhuān)業(yè)術(shù)語(yǔ)來(lái)解釋發(fā)布訂閱模式:
訂閱者把自己想訂閱的事件注冊(cè)到調(diào)度中心,當(dāng)該事件觸發(fā)時(shí)候,發(fā)布者發(fā)布該事件到調(diào)度中心(順帶上下文),由調(diào)度中心統(tǒng)一調(diào)度訂閱者注冊(cè)到調(diào)度中心的處理代碼。
在發(fā)布訂閱模式里發(fā)布者并不會(huì)直接通知訂閱者,換句話說(shuō)發(fā)布者和訂閱者彼此互不感知。
那發(fā)布者和訂閱者如何交流呢?答案是通過(guò)中間的調(diào)度中心。
發(fā)布者將消息發(fā)送給調(diào)度中心,告訴它你幫我把消息放到 Topic1中。
訂閱者告訴調(diào)度中心,我需要訂閱 topic1,你幫我留意一下。
當(dāng)有消息來(lái)了,訂閱者可以采取拉模式或者推模式來(lái)獲取消息。
有態(tài)度的總結(jié)
話不多說(shuō),先上一張圖:
從表面上看:
- 觀察者模式里只有兩個(gè)角色:觀察者和被觀察者。
- 發(fā)布訂閱模式里有三種角色:發(fā)布者、訂閱者、調(diào)度器(第三者)。
往更深層次講:
- 觀察者和被觀察者是松耦合的關(guān)系。
- 發(fā)布者和訂閱者則完全不存在耦合。
從使用層面上講:
- 觀察者模式經(jīng)常用于單個(gè)應(yīng)用內(nèi)部。
- 發(fā)布訂閱模式更多是一種跨應(yīng)用的模式(cross-application pattern),比如我們常用的消息中間件Kafka 等。
綜上:觀察者模式和發(fā)布訂閱模式本質(zhì)上都有發(fā)布訂閱的思想,但是又有一定的區(qū)別,所以我們不能將二者完全等同起來(lái)。
閑聊:冬天到了一起抱團(tuán)取暖吧~ 大家有任何技術(shù)問(wèn)題、職業(yè)發(fā)展方向問(wèn)題都可以加我的個(gè)人微信號(hào)咨詢,想進(jìn)讀者群可以備注”加群“,群里人可好了,微信搜索 smileCoder1024 值得擁有。