放過設計模式吧


太久不寫博客,都不知道咋開頭了。

主要是現在這設計模式的文章太多,而且各種爛各種曲解,看的人心煩,煩到忍不住想自己寫一個系列把它們說清楚——但是呢,轉念一想,我寫的再怎么清楚能有GoF清楚呢,怎么能有GoF的影響力大呢,GoF明明白白地擺着,還有這么多人亂搞,我又能做什么呢?所以想了半天,我覺得就寫一篇文章來吐槽好了。 - -!

說設計模式這個東西呢,不少網友跟我說起其實叫設計模式是很不對的,我也深有同感。pattern這個詞有紋理、花紋的意思,外國人買布買窗簾的時候可能會挑挑pattern,這東西說成是模式就有點過了,所以我覺得這個東西其實翻譯成《面向對象設計23招》比較好,這樣也跟我朝的《網頁特效50例》等暢銷書比較對仗。

雖然一些同學對"設計模式"這個好聽的詞被搶感到不滿,認為提到的時候應該加些修飾詞,不過為了簡單起見,咱們這里約定凡提到"設計模式"皆指GoF23模式。

設計模式針對的是面向對象的設計問題 

設計模式的另外一個巨大的問題就是它把面向對象和軟件這兩個重要的關鍵詞放進副標題里面了,兼之作者非常騷包地在里面扯了一通模式界、建築學這等事情,搞得好像這書超脫了語言和場景限制,"是一種編程思想"(加引號的原因是我覺得大師們欺騙新手最常見的手段就是故弄玄虛地說"語言都是浮雲,編程思想最重要。"),只要寫程序就必須模式一下什么的。當然GoF肯定不是故意騙大家了,其實也只能騙到那些只看正標題連副標題也不看的孩子,看了內容的話就更不會搞錯了。

但是令我驚訝的是連副標題都不看的人確實不在少數,非要用跟面向對象毫無關系的方法實現設計模式的人真的很多啊......

說了半天其實我這里想說的是設計模式是面向對象編程中特有的一些技巧,是應用五大基本原則之后(單一職責、開放封閉、里氏代換、接口隔離、依賴倒置)產生的一些設計疑難問題的解決手段。在一些非純的面向對象語言里面可能根本就不需要設計模式。

一個非常明顯的例子就是,抽象工廠、工廠方法、原型三個模式要解決的是DIP應用以后的創建對象難題。

很多文章根本就不管什么DIP,舉了一堆所謂"生活中的例子",神馬造零件做漢堡的copy作業之類的,尼瑪啊,這跟那些生活有毛關系啊,程序員的生活難道不就是寫程序么?寫程序難道不就必然要用到DIP么?用到DIP只依賴接口這東西不能new才需要這幾個模式的啊,人家模式名字里面帶工廠倆字沒聽說實現的業務就一定要跟生產有關系啊。

基於這種不知所謂的邏輯,這幾個模式當然也可以用在JS、C什么的里面啦,因為JS也難免有描述鞋廠麥當勞的時候嘛。於是這些模式就華麗麗地成為了一種思想,抽象工廠變成了"描述一個一種對象可以產生另外一種對象這樣的業務邏輯",原型變成了"描述一個對象可以copy自身這樣的業務邏輯",更加華麗地是,這些業務邏輯模式還能被扭來扭曲實現成完全符合GoF上UML圖的類結構啊.....

說到正經事,既然是因為遵循DIP才引入的幾個模式,在JS這個沒有接口的面向對象語言中,自然不存在使用的需求了。(但有趣地是,JS里面把原型作為幾乎是唯一地創建對象手段,與本文主題無關,就不多說了。)而C++有模板這樣強大的特性,很大程度上也不需要簡單工廠和工廠方法(抽象工廠還是需要的)。同樣的道理,擁有delegate和Event的C#里面也沒有使用觀察者模式的必要。

語義比UML重要1000倍

設計模式里面最不容易誤解的就是UML了,凡講設計模式的文章,就算扯得再不靠譜,一般UML也是對的...... 好吧UML也是對的這件事實在太容易,甚至比如策略模式和狀態模式和橋接模式的UML都是基本一樣的。

嗯,於是囧的事情出現了,比如http://en.wikipedia.org/wiki/Strategy_pattern 在煞有介事地對比策略和橋接到底有何不同。尼瑪啊!!!!我怎么沒想明白一個叫"實現",一個叫"算法",這倆東西腫么就能有交叉呢?

只看UML是不少設計模式文章的通病,嗯,通常情況下這時候"生活中的例子"又會登場了,語義則會被華麗麗地無視。最為悲慘的兩個模式就是策略模式和橋接模式了,看來"算法"、"實現"、"抽象"這些詞實在不太好理解。為了夠"生活",譬如買油和買鹽這等完全不相干的功能就被戴上了算法的帽子,GoF說的好"本模式使得算法可以獨立於使用它的Client而變化",Client表示很無奈啊,就換了個算法而已,連結果都變了是怎么回事啊,剛才算的還是a+b,尼瑪你一換算法結果變成a*b了?(嗯, 我在吐槽http://en.wikipedia.org/wiki/Strategy_pattern) 卧槽你想說a+b和a*b都是calculate這件事么?你怎么不干脆把所有方法都叫dosomething啊,那樣全世界所有的事情都可以叫不同策略了啊!

橋接模式更悲劇了,"抽象"和"實現"這倆詞怎么聽着這么像接口和具體類啊,難道說......橋接模式其實就是LSP?再一看UML真簡單啊,這不就是組合么?於是亂搞一個"生活中的例子"把UML對上就成了!我承認英文里面這倆詞跟實現接口、抽象類有點像,翻譯成中文更沒區別了,但是GoF里面不是tmd還有例子呢么?不是還有解釋呢么?GoF那Window的例子是多么的明顯,抽象是業務相關的,實現是系統底層相關的。 

一些其它的模式和誤解

Flyweight經常被以C#的字符串為例而搞成"神秘地節約內存方案",或者以內存池為例搞成只有外部狀態的假對象。辨識正確的Flyweight模式實現的關鍵要素是內部狀態和外部狀態是否俱全。

Composite模式經常被誤解為樹形結構,辨識Composite模式的關鍵在於語義,幾個X的組合是否仍然是X,而不是被X包含。舉例子來說,幾個幾何圖形的組合仍然是幾何圖形,而幾個HTML節點的組合就不是一個HTML節點。

Decorator模式經常被搞成拼字符串用的(尼瑪,這活還是交給StringBuilder之類的東西吧......),辨識Decorator的關鍵一是被裝飾的是類而不是方法,二是語義上是否可以被再次裝飾。 

結語 

設計這件事情很難用語言表達,因此要講清楚設計是一件非常困難的事情,在博客園出現的設計模式文章我經常跑去給負面評論......但屢屢被教育"不要為了模式而模式"、"你對設計模式的理解,還僅限於GoF"、"只要遵循基本設計原則就可以"。(大約我朝受"無招勝有招"文化熏陶太久,導致大家還沒等學會招呢,先奔無招去了......)設計模式的本意之一是提供一套通用的設計詞匯,但是顯然時至今日(至少在我朝),它自身都被各種歪曲誤解。希望大家能夠一起努力,一是以身作則,寫文章的時候更嚴謹,二是擦亮眼睛,看文章的時候多查資料,消滅設計模式的各種歪解。

附上一張我的設計模式書的照片,以證明我確實讀過GoF(挖咔咔咔咔)

 

看了朋友的一些評價覺得有必要提一下,

寫此文的意思絕對不是要初學者不寫設計模式的文章

我想表達的意思是(不限於設計模式)讀書寫文章的時候,應該更加嚴謹,不理解的地方,不能含糊代過甚至憑想當然,這樣不論對人對己,都是更容易進步。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM