王垠:解密“設計模式”

王垠發表於2013-03-08

來源:王垠的部落格

有些人問我,你說學習作業系統的最好辦法是學習程式設計。那我們是不是應該學習一些“設計模式”(design patterns)。這是一個我很早就有定論,而且經過實踐檢驗的問題,所以想在這裡做一個總結。

總的來說,如果光從字面上講,程式裡確實是有一些“模式”可以發掘的。因為你總是可以借鑑以前的經驗,用來構造新的程式。你可以把這種經驗叫做“模式”。可是自從《設計模式》(通常叫做 GoF,“Gang of Four”,“四人幫”)這本書在 1994 年發表以來,“設計模式”這個詞有了新的,扭曲的含義。它變成了一種教條,帶來了公司里程式的嚴重複雜化以及效率低下。

王垠:解密“設計模式”

GoF 借鑑的是一個叫 Christopher Alexander 的建築師的做法。Alexander 給一些建築學裡的“設計模式”起了名字,試圖讓建築師們有一些“共同語言”。可惜的是,Alexander 後來自己都承認,他的實驗失敗了。因為這些固定的模式,並沒能有效地傳遞精髓的知識,沒能讓新手成長為出色的建築師。

照搬模式東拼西湊,而不能抓住事物的本質,沒有“靈感”,其實是設計不出好東西的。這就像照搬“模版”把作文寫得再好,也成不了作家一樣。

我孤陋寡聞,當聽說這本書的時候,我已經學會了函數語言程式設計,正在 Cornell 讀 PhD,專攻程式語言設計。有一天由於好奇這書為什麼名氣這麼大,我從圖書館借了一本回來看。我很快的發現,其實這本書的作者只是給早已經存在的程式設計方法起了一些新的名字而已。當時我就拿起一張紙,把所有的20來個設計模式跟我常用的程式設計概念做了一個對映。這個對映居然是“多對一”(many-to-one)的。也就是說,多個 GoF 設計模式,居然只對應同一個我每天都用的概念。有些概念是如此的不值一提,以至於我根本不需要一個名字來描述它,更不要說多個名字!

其中極少數值得一提的“模式”,也許是 visitor 和 interpreter。很可惜的是,只有很少的人明白如何使用它們。所謂的 visitor,本質上就是函式式語言裡的含有“模式匹配”(pattern matching)的遞迴函式。在函式式語言裡,這是多麼輕鬆的事情。可是因為 Java 沒有模式匹配,所以很多需要類似功能的人就得使用 visitor pattern。為了所謂的“通用性”,他們往往把 visitor pattern 搞出多層繼承關係,讓你轉幾道彎也搞不清楚到底哪個 visitor 才是幹實事的。

其實,函式式語言的研究者們早就知道 visitor pattern 是怎麼得來的。如果你想知道如何從無到有,一步一步“發明”出 Java 的 visitor pattern,可以參考?Dan Friedman?跟他的學生 Matthias Felleisen 合寫的的另一本“小人書”《A Little Java, A Few Patterns》(發表於 1997 年)。<wbr><wbr>

王垠:解密“設計模式”

而 interpreter (直譯器)模式呢?看了作者們寫的例子程式之後,我發現他們其實並不會寫直譯器,或者說他們不知道如何寫出優雅的,正確的直譯器。如果你想知道如何寫出好的直譯器,可以參考我的博文《怎樣寫一個直譯器》。

你說我在貶低這本書的真正價值,因為 GoF 說了:“我們的貢獻,就是給這些程式設計方式起名字。這樣讓廣大程式設計師有共同的語言。” 如果這也叫貢獻的話,我就可以寫本書,給“空氣”,“水”,“豬肉”這些東西全都起個新名字,讓大家有“共同的語言”。這不是搞笑嗎。

這不是我的一家之言,Peter Norvig 在 1998 年就做了一個演講,指出在“動態語言”裡面,GoF 的20幾個模式,其中絕大部分都“透明”了。也就是說,你根本感覺不到它們的存在。這就像我剛才告訴你的。

王垠:解密“設計模式”

在這裡 Norvig 的觀點是正確的,不過需要小心一個概念錯誤。Norvig 對“靜態語言”的概念是有侷限性的。有的靜態語言其實也能傳遞函式作為引數,而且不像 Java 那樣什麼都得放進 class 裡。這樣的靜態語言,其實也可以避免大部分 GoF 設計模式。而“動態語言”這個概念,在程式語言的理論裡面,其實是沒有明確的定義的。“動態語言”其實也能進行某些“靜態型別檢查”。不過在 1998 年,我還是個啥都不懂的屁孩,所以這裡就不跟 Norvig 大叔計較了。

既然老人們都有歷史侷限性,那麼為啥我還跟 GoF 找茬?本來這本書很老了,如果沒有人再被它誤導的話,這篇博文也就不必存在了。可是當我在 Google 實習的時候,我發現幾乎每個程式設計師的書架上都有一本 GoF!我在 Google 實習了兩次,第一次的時候程式碼全都是我一個人寫的,所以沒有使用任何 GoF 設計模式。程式碼直接,精巧而簡單。當我第二次回到 Google,發現我的程式碼裡已經被加入了各種 factory,visitor,…… 其實啥好事也沒做,只不過讓我的程式碼彎了幾道彎,讓人難以理解。

可見一本壞書,毀掉的不只是一代程式設計師。鑑於如此,特發此文。各位新手,希望你們敲響警鐘,不要再走上這條老路,寫出程式碼來讓大家痛苦。

至於如何學會寫真正好的程式碼,我在另一篇博文裡再講。

相關文章