1. 程式人生 > >自我聯想學設計模式(初級版)-1-觀察者模式

自我聯想學設計模式(初級版)-1-觀察者模式

如果單純的看書,其實很容易陷入到各種概念中去,最終導致似乎懂了,但實際開始使用的時候又有各種問題。這個版本的設計模式只從實用來入手,就是在各種情況下,根據聯想快速的代入這個模式,能夠迅速用起來,轉化為程式碼。所以這個版本的設計模式都以現實中的例子自己聯想。

假設我以去電影院看電影為例,因為觀察者嘛,就是看東西,所以這裡以看電影為例。

這就是觀察者的模式了。

這裡我們有目標:電影毒液。有觀察者:觀影者N個。

這就完了嗎?該怎麼轉化為程式碼呢?

那麼我再仔細想想,目標也就是電影毒液。

它是什麼?該怎麼轉化為程式碼?

假使我現在還不知該轉化為程式碼,我不管那麼多我先建立一個類,後續怎麼聯絡起來,後續再看。

於是我先建立一個MovieVeno類。

現在有了Movie類,該怎麼和觀影者聯絡起來呢?

假使現在還沒有思路,我不管那麼多,先建立一個類再說,反正不管是誰都是一個物件嘛!如果建立錯了,我可以刪掉啊。

如此,便建立起了兩個類。

然後呢?這兩個類如何建立關聯呢?其實在程式碼裡,我們知道,說兩個類有關聯,就是能互相訪問到對方,無論是通過訊息傳遞,或者彼此有對方的引用。

既然如此,我們知道電影院一般都是一個電影多個人看,我們可以給每個人都持有這個電影的引用,也可以給這個電影持有每個人的引用。

這裡呢,我通過一些朦朦朧朧的記憶,依稀記得,觀察者模式是目標持有觀察者的引用。

那麼我就讓電影持有觀影人的引用吧。所謂引用在這裡指的就是指標。如果有人有疑問,為什麼是指標?那不是指標還能是什麼呢?

所以:

在這裡我給觀影人加了座位編號的屬性,給電影加了一個儲存觀影人引用的map。

這裡UML的類圖使用聚合關係。意味著觀影人可以離開電影單獨存在。大家只是因為看這部電影所以才聚在一起的,看完也就散了。

好了目前看起來不錯。等等。怎麼總感覺哪裡怪怪的。

看起來兩者似乎關聯起來了,但是如果轉化為程式碼呢?MovieVeno只是有了這個map,但是還沒有新增的操作啊,我們仔細回想看電影的過程,還有十分鐘開場了,你拿著爆米花和可樂,等女友上完洗手間之後,兩人入場了。

對!入場啊!怎麼表示入場呢。加個函式啊。

哎?仔細看看明明是電影類,怎麼有個進入觀影室的函式。

對啊,如果你不進入觀影室,你站在電影院外面,你在網咖裡,怎麼看電影?

在現實世界裡你和什麼產生關聯,其實就是觸碰嘛!精神觸碰,身體觸碰,眼神觸碰等等。

要看電影就要去電影院。

但在電影類裡有你個進入觀影室的函式確實有點怪。怎麼辦?

我們再想想,如果沒有靈機一動,恍然大悟,那就什麼都不做,繼續往下看。

好,現在進入電影院了。電影開場了。我們該看電影了。

可是放在程式碼裡怎麼表現呢?首先添加個看電影的函式吧。

這能表現出來麼?也表現不出來,因為沒有資料表明看哪部電影啊?那上面不是有個箭頭表示他們有聯絡嗎?

是啊,但是程式碼裡可沒有箭頭啊。所以我們還是要把電影的資料給觀影者的。

好了,我們開始看電影了。

兩個貌似Loser的人擊敗了兩個貌似高手的人。電影結束了。該離場了。

等等,離場怎麼表示?新增函式。

到這裡是不是該完事了。

看起來,應該完事了,但就是電影類裡入場和離場函式有點怪。因為觀影室才是我們觀影的地方,我們進去和離開的地方也是觀影室。

總覺得虧欠了觀影室什麼那麼點東西。

哎,算了,下次再說吧,畢竟程式碼著急上線。

看完了電影《毒液》之後,電影院的人換片啦,換成張藝謀的《影》,結果發現我們又要新建影片和觀察者列表,你會發現,他們播放《影》的地方還是剛剛播放《毒液》的那個觀影室,然後還會播放《無雙》,那麼我們就會發現每播放一次電影,就要新建觀察者列表,但如果不考慮效率,也並不是不可以。

但是我們還是會發現之前一直讓我們奇怪的地方,因為我們觀察的是電影沒錯,可是我們沒有在程式碼裡表現出觀影室這個事物,也即是說,從程式碼裡其實我們很可能是在露天觀影。其實即使是露天觀影,我們的資訊也不足,因為全世界露天的地方太多了,能播放電影的地方何止一個?更何況很明顯我們不是,我們就是在中影電影院的觀影室裡看的。

所以不能忽視這個觀影室,現在我們有加個觀影室類。

現在多了一個類,我們要把這個電影和這個觀影室關聯起來,怎麼關聯起來,因為我們看的這部電影就是在這個觀影室裡放的,所以我們把它放入這個觀影室裡,讓他通過這種最簡單的方式關聯起來。而且,觀影室裡的電影是會不斷更換的,所以我們用當前的電影來表示正在播放或者說觀影者正在觀看的電影。

電影的內容雖然不同,但是存放的介質,有片頭和片尾,被廣電總局稽核通過,等等都是有統一標準的,換成程式碼也就是有統一介面的。觀影室不能只放這一部電影,而是滿足這個條件的都可以播放,所以再改程式碼。

同樣,觀影者也不是隻能看《毒液》這一部,任何電影都可以看。所以,再改程式碼。

現在我們再看一下,其實就會發現,之前的在電影類裡有入場和出場函式為什麼奇怪了。

我們再改程式碼:

而顯然,能夠進入的玩家都是進入的觀影室,而且觀影室的位置也決定了觀影者的數目上限,這和放什麼電影沒關係。

再改程式碼。

到這裡我們就會發現,其實我們和電影本身並沒有什麼關係,我們看到的只是電影的內容,但是電影的播放,什麼時候播放,在哪裡播放都不是我們控制的了的,我們只是進入那個觀影室坐在座位上等待而已。那個觀影室放了什麼電影,我們就看的是什麼電影,放了《毒液》我們就看毒液,即使我們買的是《毒液》的票,可如果對方放的是《影》,我們其實長露出看不了毒液的。

所以我們應該和觀影室聯絡起來,當觀影室切換電影時,我們收到通知,進去看它馬上要播放的電影就行了。

再改程式碼。

這樣,我們再加一個切換影片和通知觀影者入場觀看影片的函式。

當觀影室ChangeMovie的時候,呼叫自己的Notify函式,因為觀影室的wMap裡有每個觀影者的引用,所以遍歷wMap,呼叫每個觀影者的WatchMovie把當前切換的影片傳給他們,他們就可以看了。

我們發現,其實程式碼描述的就是現實生活中的事,沒有什麼新鮮的東西,用生活中類比的話,我們就可以把這個模式類比出來。

一個觀察的目標類,目標裡有觀察者的引用列表有新增觀察者和刪除觀察者的函式有更新自己資料的函式有通知觀察者更新資料的函式。

一個觀察者類,有更新自己資料的函式。在被通知更新時呼叫。

這就是觀察者。