GoF的[設(shè)計(jì)模式]是經(jīng)典著作,有人看了好多遍仍然說(shuō)沒(méi)有看懂,許多人看懂了一些模式但不知道如何應(yīng)用……這里,我拋磚引玉,討論一下如何學(xué)習(xí)設(shè)計(jì)模式。
注:《Design Patterns: Elements of Reusable Object-Oriented Software》(即后述《設(shè)計(jì)模式》一書(shū)),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。這幾位作者常被稱為"四人組(Gang of Four)",簡(jiǎn)稱:GoF
①學(xué)習(xí)技巧
學(xué)習(xí)設(shè)計(jì)模式時(shí),有一些技巧能夠幫助你快速理解設(shè)計(jì)模式。
a)使用較簡(jiǎn)單的面向?qū)ο蟮恼Z(yǔ)言如Java、C#。GoF的[設(shè)計(jì)模式]實(shí)質(zhì)上是面向?qū)ο蟮脑O(shè)計(jì)模式。[GoF·1.1]中提到“程序設(shè)計(jì)語(yǔ)言的選擇非常重要,它將影響人們理解問(wèn)題的出發(fā)點(diǎn)”。從學(xué)習(xí)設(shè)計(jì)模式的角度看,Java和C#較C++更容易一些。比如Java接口等,能夠更有效展現(xiàn)設(shè)計(jì)模式的意圖。
b)使用工具BlueJ。BlueJ的好處,就是提供了簡(jiǎn)單的類圖。正如我在簡(jiǎn)明設(shè)計(jì)模式Java中所做的,較少去專門(mén)畫(huà)類圖,而是在BlueJ中截圖。在學(xué)生上機(jī)編寫(xiě)演示程序時(shí),常常先看他的類圖,以判斷他的程序是否正確,必要時(shí)再看源代碼。
c)日常生活的隱喻。用一些實(shí)際生活中的例子來(lái)說(shuō)明某某模式,能夠讓你快速掌握某模式的目的和實(shí)現(xiàn)代碼的結(jié)構(gòu)。同時(shí),你要認(rèn)識(shí)到,這種隱喻如同告訴你(2+3)2=22+2*2*3+32,你需要自己舉一反三,得出(a+b)2=a2+2ab+b2。在實(shí)際工作中的模式的具體應(yīng)用,則相當(dāng)于應(yīng)用代數(shù)公式。
d)動(dòng)手實(shí)踐和懷疑精神??达@淺的參考書(shū)或上網(wǎng)查閱資料時(shí),要自己敲(復(fù)制也可以)代碼并運(yùn)行,要多修改別人的源代碼提出自己的觀點(diǎn):為什么書(shū)中不這樣設(shè)計(jì)、為什么要那樣設(shè)計(jì);如果增添一些方法、方法參數(shù)、或成員變量會(huì)如何?必須要自己親自動(dòng)手,起碼要運(yùn)行。另外,要敢于向博主提問(wèn)、拍磚。你甚至可以質(zhì)疑GoF的某些章節(jié)的解說(shuō)和意圖,更何況一些博主呢。
②基礎(chǔ)知識(shí)
這些知識(shí)讓你知道,設(shè)計(jì)模式好在何處。
a)面向?qū)ο蠓妒健R簿褪侨藗儌髡f(shuō)的思想。封裝、繼承和多態(tài)這些東西,在我看來(lái)比if、for等稍微高一點(diǎn),也屬于語(yǔ)法問(wèn)題。面向?qū)ο缶幊桃莆盏娜笤瓌t是柏拉圖(Plato)原則、里氏(Liskov)替換原則和Parnas原則。這三個(gè)原則其實(shí)非常簡(jiǎn)單。任何原則,你覺(jué)得很難一見(jiàn)鐘情,很難快速認(rèn)同,那它就不會(huì)是好原則。
b)設(shè)計(jì)原則。許多人列舉了7大原則,如單一職責(zé)原則、開(kāi)閉原則、里氏代換原則、依賴倒轉(zhuǎn)原則、接口隔離原則、合成復(fù)用原則、迪米特法則。LSP,我將它提升為面向?qū)ο蠓妒降?大基石之一;單一職責(zé)和接口隔離,主要作為面向?qū)ο蠓治?OOA時(shí)職責(zé)劃分所遵循的原則,此時(shí)你可以不太在意。依賴倒轉(zhuǎn)原則,我把它作為垃圾扔掉,因?yàn)殚_(kāi)閉原則或者直接地說(shuō)“依賴于抽象類型原則”已經(jīng)包含了依賴倒轉(zhuǎn)原則的精華,而依賴倒轉(zhuǎn)原則的糟粕由IoC繼承。當(dāng)然,回調(diào),我很強(qiáng)調(diào)。所以,你要掌握的有抽象依賴原則(OCP)、單向依賴原則(含對(duì)回調(diào)的學(xué)習(xí))和依賴原則(合成復(fù)用原則、迪米特法則)。
c)UML的初步了解。這是學(xué)習(xí)設(shè)計(jì)模式的工具。在早期,你甚至可以僅了解BlueJ的相關(guān)圖示,也就10分鐘的事情。
③境界
《五燈會(huì)元》卷十七中,有一則唐朝禪師青原惟信禪師的語(yǔ)錄:“老僧三十年前未參禪時(shí),見(jiàn)山是山,見(jiàn)水是水。及至后來(lái)親見(jiàn)知識(shí),有個(gè)入處,見(jiàn)山不是山,見(jiàn)水不是水。而今得個(gè)休歇處,依前見(jiàn)山只是山,見(jiàn)水只是水。”
a)仔細(xì)研究GoF的[設(shè)計(jì)模式],逐個(gè)學(xué)習(xí)其意圖和結(jié)構(gòu),是一個(gè)抱著字典學(xué)習(xí)英語(yǔ)的方式。見(jiàn)山是山,見(jiàn)水是水,導(dǎo)致你可能在實(shí)際工作中生搬硬套、東施效顰。
b)建議從簡(jiǎn)單的場(chǎng)景出發(fā),自己發(fā)現(xiàn)或設(shè)計(jì)出某種模式。你從中體會(huì)該模式是如何解決問(wèn)題的,這樣,該模式成為你自己的東西,你才不會(huì)出現(xiàn)知易行難的問(wèn)題。所有的設(shè)計(jì)模式不過(guò)是基本原則和理念在特定場(chǎng)合的應(yīng)用。你可能不知道某個(gè)設(shè)計(jì)模式的名字,但是你知道它一切的優(yōu)缺點(diǎn)和變體以及應(yīng)用場(chǎng)合。見(jiàn)山不是山,見(jiàn)水不是水。
c)你對(duì)基本原則和理念融會(huì)貫通,你可以惋惜:“我找到一種模式,原來(lái)在[設(shè)計(jì)模式](其實(shí)是某個(gè)特殊的書(shū)、文章提到的模式)中早就有了這種模式”。這時(shí),模式不模式又如何呢?反模式又怎樣??匆?jiàn)一個(gè)模式,你會(huì)說(shuō):“嗯,這是一種有用的模式”。見(jiàn)山只是山,見(jiàn)水只是水。