計模式復(fù)習(xí)總圖:七大原則與二十三種模式完整知識骨架)
簡介這份《大話設(shè)計模式復(fù)習(xí)》文檔面向具備一定面向?qū)ο缶幊袒A(chǔ)、工作1至3年的研發(fā)人員系統(tǒng)梳理設(shè)計模式的核心知識體系。內(nèi)容從設(shè)計模式的定義、分類、特點與應(yīng)用場景切入詳細(xì)講解單一職責(zé)、開放-封閉、依賴倒轉(zhuǎn)、里氏代換、迪米特法則、合成/聚合及接口隔離七大設(shè)計原則并深入剖析抽象工廠、策略、外觀、適配器、組合、單例、中介者七種常用模式以及其余十五種模式的UML類圖、基礎(chǔ)代碼與實例。文檔還橫向?qū)Ρ炔煌J降牟町惪偨Y(jié)模式選擇的關(guān)鍵維度并附練習(xí)題與模擬試卷輔助鞏固。資源包為單個docx文件約3.66MB結(jié)構(gòu)完整、目錄清晰便于按章節(jié)檢索學(xué)習(xí)。目前已有191人學(xué)習(xí)適合希望提升代碼可維護(hù)性、可擴展性與復(fù)用性并在實際項目中靈活選用設(shè)計模式的開發(fā)者參考。1. 設(shè)計模式復(fù)習(xí)總圖從七大原則到二十三種模式的完整知識骨架設(shè)計模式這塊內(nèi)容最怕的不是記不住而是腦子里沒有一張總圖。很多人復(fù)習(xí)時翻開資料就從單例模式開始背背到代理模式已經(jīng)忘了抽象工廠在講什么最后腦子里只剩一堆零散的類圖。真正有效的復(fù)習(xí)路徑是先建立分類坐標(biāo)系創(chuàng)建型管對象怎么生結(jié)構(gòu)型管類與對象怎么拼行為型管對象之間怎么通信與分責(zé)。三大類共二十三種經(jīng)典模式加上七大設(shè)計原則作為底層判據(jù)再配合易混淆模式對比表才構(gòu)成一個可檢索、可推導(dǎo)的復(fù)習(xí)體系。這份筆記梳理的就是這樣一條從原則到模式、從單模式拆解到跨模式對比的完整鏈路適合已經(jīng)寫過面向?qū)ο蟠a、正在系統(tǒng)復(fù)習(xí)或準(zhǔn)備面試的人拿來當(dāng)查漏補缺的地圖用。2. 七大設(shè)計原則模式背后的判據(jù)與易混邊界2.1 七條原則各自管什么設(shè)計原則不是拿來背的是拿來判斷“這個模式為什么長這樣”的。梳理下來會發(fā)現(xiàn)二十三種模式幾乎都能回溯到某幾條原則的約束。原則一句話核心典型落地模式單一職責(zé) SRP一個類只有一個引起變化的原因計算器運算類拆分開放-封閉 OCP對擴展開放對修改關(guān)閉策略模式新增算法依賴倒轉(zhuǎn) DIP高低層都依賴抽象細(xì)節(jié)依賴抽象工廠模式依賴產(chǎn)品接口里氏代換 LSP子類必須能替換父類且行為契約不變正方形與矩形的經(jīng)典反例迪米特法則 LOD不和陌生人說話通過第三者轉(zhuǎn)發(fā)中介者模式合成/聚合 CARP優(yōu)先組合而非繼承裝飾模式接口隔離 ISP用多個專門接口代替一個總接口動物接口拆分為飛行、陸地這張表建議反復(fù)看因為后面每一種模式的分析都會回到這里。比如抽象工廠模式它同時踩中依賴倒轉(zhuǎn)和合成/聚合但在新增產(chǎn)品等級結(jié)構(gòu)時會違反開放-封閉——這就是原則之間的張力也是考試和面試最愛問的地方。2.2 最容易搞混的三組原則依賴倒轉(zhuǎn) vs 里氏代換。依賴倒轉(zhuǎn)講的是“依賴誰”——依賴抽象不依賴具體里氏代換講的是“替換后還行不行”——子類替換父類后行為不能變。一個管方向一個管契約。迪米特法則 vs 接口隔離。迪米特管的是“少跟不相關(guān)的類直接通信”接口隔離管的是“別讓類依賴它用不到的方法”。前者是通信路徑問題后者是接口粒度問題。合成/聚合 vs 開放-封閉。合成/聚合是實現(xiàn)開放-封閉的手段之一——通過組合而非繼承來擴展功能裝飾模式就是典型。但開放-封閉還可以通過策略、工廠等模式實現(xiàn)所以兩者不是一回事。提示復(fù)習(xí)原則時不要孤立背定義每一條都找一個具體模式作為錨點回憶時先想模式再反推原則比正著背快得多。3. 七大重點模式拆解抽象工廠、策略、外觀、適配器、組合、單例、中介者3.1 抽象工廠模式產(chǎn)品族的創(chuàng)建接口抽象工廠的核心是“產(chǎn)品族”概念。所謂產(chǎn)品族是指位于不同產(chǎn)品等級結(jié)構(gòu)、功能相關(guān)聯(lián)的產(chǎn)品組成的家族。比如數(shù)據(jù)庫訪問組件中User 表和 Department 表就是兩個產(chǎn)品等級結(jié)構(gòu)而 SqlServer 系列和 Access 系列就是兩個產(chǎn)品族。角色分工抽象工廠 AbstractFactory聲明創(chuàng)建產(chǎn)品族的方法如 createProductA()、createProductB()具體工廠 ConcreteFactory實現(xiàn)工廠方法創(chuàng)建具體產(chǎn)品族抽象產(chǎn)品 AbstractProduct定義產(chǎn)品接口具體產(chǎn)品 ConcreteProduct實現(xiàn)抽象產(chǎn)品接口內(nèi)部包含業(yè)務(wù)邏輯// 抽象工廠接口聲明創(chuàng)建兩個產(chǎn)品等級結(jié)構(gòu)的方法 public interface AbstractFactory { AbstractProductA createProductA(); AbstractProductB createProductB(); } // 具體工廠1創(chuàng)建產(chǎn)品族1 public class ConcreteFactory1 implements AbstractFactory { public AbstractProductA createProductA() { return new ProductA1(); } public AbstractProductB createProductB() { return new ProductB1(); } } // 客戶端只依賴抽象工廠和抽象產(chǎn)品 AbstractFactory factory1 new ConcreteFactory1(); AbstractProductA a1 factory1.createProductA(); AbstractProductB b1 factory1.createProductB();參數(shù)說明createProductA() 和 createProductB() 分別對應(yīng)兩個產(chǎn)品等級結(jié)構(gòu)具體工廠決定返回哪個產(chǎn)品族的實例。客戶端只持有 AbstractFactory 類型引用切換產(chǎn)品族時只需換一個具體工廠。適用場景對象屬于同一產(chǎn)品族需一起使用系統(tǒng)不依賴具體產(chǎn)品類系統(tǒng)只消費某一個產(chǎn)品族。優(yōu)點是分離接口與實現(xiàn)符合依賴倒轉(zhuǎn)缺點是新增產(chǎn)品等級結(jié)構(gòu)需修改抽象工廠和所有具體工廠違反開放-封閉。AbstractFactory 與 Factory 的區(qū)別AbstractFactory 為創(chuàng)建一組相關(guān)或依賴的對象提供接口Factory 為一類對象提供創(chuàng)建接口。一個管“族”一個管“個”。3.2 策略模式算法的可互換封裝策略模式的定義是定義一系列算法將每個算法封裝到具有公共接口的獨立類中使其可互換。類的劃分基礎(chǔ)是抽象具有相同屬性和功能的對象的抽象集才是類。interface Strategy { void doAlgorithm(); } class StrategyA implements Strategy { public void doAlgorithm() { /* 算法A */ } } class Context { private Strategy strategy; public void setStrategy(Strategy s) { strategy s; } public void executeStrategy() { strategy.doAlgorithm(); } }Context 持有 Strategy 引用客戶端通過 setStrategy 切換算法。商場收銀系統(tǒng)中正常收費、滿減、打折就是三個具體策略收銀臺是 Context。策略模式的關(guān)鍵在于客戶端必須知道有哪些策略可選并主動選擇。這和狀態(tài)模式不同——狀態(tài)模式的狀態(tài)切換通常由上下文或狀態(tài)自身驅(qū)動客戶端不感知。3.3 外觀模式與適配器模式一個簡化一個轉(zhuǎn)換外觀模式為子系統(tǒng)提供統(tǒng)一的高層接口讓子系統(tǒng)更容易使用。它不改變子系統(tǒng)本身只是加了一層門面。適配器模式則是將一個類的接口轉(zhuǎn)換成客戶端期望的另一個接口解決的是接口不兼容問題。兩者的核心區(qū)別外觀是“簡化調(diào)用”適配器是“轉(zhuǎn)換接口”。外觀模式下客戶端直接調(diào)用外觀類不關(guān)心子系統(tǒng)內(nèi)部適配器模式下客戶端調(diào)用目標(biāo)接口適配器內(nèi)部委托被適配者。3.4 組合模式與單例模式樹形結(jié)構(gòu)與全局唯一組合模式將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次關(guān)系使得客戶端對單個對象和組合對象的使用具有一致性。典型場景是文件系統(tǒng)、UI 控件樹。單例模式保證一個類只有一個實例并提供全局訪問點。復(fù)習(xí)時重點注意多線程環(huán)境下的實現(xiàn)方式差異餓漢式在類加載時就創(chuàng)建實例線程安全但不支持延遲加載懶漢式需要雙重檢查鎖定或靜態(tài)內(nèi)部類來兼顧延遲加載和線程安全。3.5 中介者模式把網(wǎng)狀依賴變成星形依賴中介者模式用一個中介對象封裝一系列對象之間的交互使各對象不需要顯式地相互引用。迪米特法則在這里體現(xiàn)得最明顯——同事類之間不直接通信全部通過中介者轉(zhuǎn)發(fā)。典型場景是 GUI 對話框中多個控件之間的聯(lián)動一個下拉框的選擇影響按鈕是否可用、文本框是否可編輯。如果沒有中介者每個控件都要持有其他控件的引用依賴關(guān)系變成網(wǎng)狀引入中介者后變成星形每個控件只認(rèn)識中介者。4. 剩余十五種模式速覽從簡單工廠到訪問者4.1 創(chuàng)建型補充簡單工廠、工廠方法、原型、建造者簡單工廠模式嚴(yán)格來說不算 GoF 二十三種之一但它是理解工廠方法的基礎(chǔ)。簡單工廠用一個工廠類根據(jù)參數(shù)決定創(chuàng)建哪種產(chǎn)品工廠方法將創(chuàng)建延遲到子類每個具體工廠對應(yīng)一種產(chǎn)品抽象工廠則對應(yīng)產(chǎn)品族。建造者模式與工廠模式的區(qū)別工廠模式關(guān)注“創(chuàng)建什么產(chǎn)品”建造者模式關(guān)注“如何一步步組裝一個復(fù)雜對象”。建造者通常有 buildPartA()、buildPartB()、getResult() 這樣的步驟接口適合構(gòu)建過程穩(wěn)定但表示可變的場景。原型模式通過克隆現(xiàn)有對象來創(chuàng)建新對象適用于創(chuàng)建成本高或需要保存對象狀態(tài)的場景。與單例模式的區(qū)別單例保證全局唯一原型保證可以復(fù)制出多個相同實例。4.2 結(jié)構(gòu)型補充裝飾、代理、橋接、享元裝飾模式通過組合而非繼承來動態(tài)擴展對象功能符合合成/聚合原則。代理模式為其他對象提供一種代理以控制對這個對象的訪問典型場景是遠(yuǎn)程代理、虛擬代理、保護(hù)代理。裝飾器與代理的區(qū)別裝飾器關(guān)注“增強功能”代理關(guān)注“控制訪問”。裝飾器通常由客戶端主動組合代理通常對客戶端透明。橋接模式將抽象部分與實現(xiàn)部分分離使它們可以獨立變化。享元模式通過共享技術(shù)有效支持大量細(xì)粒度對象關(guān)鍵是區(qū)分內(nèi)部狀態(tài)可共享和外部狀態(tài)不可共享。4.3 行為型補充模板方法、觀察者、狀態(tài)、命令、責(zé)任鏈、備忘錄、訪問者、迭代器、解釋器模板方法模式在父類定義算法骨架將某些步驟延遲到子類實現(xiàn)。觀察者模式定義一對多依賴當(dāng)一個對象狀態(tài)改變時所有依賴者收到通知。狀態(tài)模式允許對象在內(nèi)部狀態(tài)改變時改變行為看起來像換了類。命令模式將請求封裝為對象支持撤銷和隊列。責(zé)任鏈模式將請求沿處理者鏈傳遞直到被處理。備忘錄模式在不破壞封裝的前提下捕獲并恢復(fù)對象內(nèi)部狀態(tài)。訪問者模式在不改變元素類的前提下定義新操作。迭代器模式提供順序訪問聚合元素的方法。解釋器模式給定語言定義文法表示及解釋器。注意行為型模式最容易混的是策略 vs 狀態(tài)、觀察者 vs 中介者、責(zé)任鏈 vs 中介者下一章的對比表專門處理這些。5. 易錯與易漏點模式對比中最容易翻車的五組關(guān)系5.1 策略 vs 狀態(tài)誰決定切換易漏點把策略模式和狀態(tài)模式當(dāng)成一回事。為什么漏兩者都有 Context 和抽象接口UML 結(jié)構(gòu)幾乎一樣。怎么補記住切換的主動權(quán)不同——策略模式由客戶端選擇并設(shè)置策略狀態(tài)模式由上下文或狀態(tài)自身驅(qū)動切換客戶端通常不感知狀態(tài)變化。5.2 適配器 vs 裝飾器 vs 代理結(jié)構(gòu)相似但意圖不同易漏點三者都是“包一層”分不清什么時候用哪個。為什么漏UML 類圖結(jié)構(gòu)高度相似都是持有被包裝對象的引用。怎么補適配器改變接口裝飾器增強功能代理控制訪問。適配器通常包裝不兼容的接口裝飾器包裝同接口對象并添加行為代理包裝同接口對象并控制調(diào)用時機。5.3 觀察者 vs 中介者一個廣播一個轉(zhuǎn)發(fā)易漏點把觀察者和中介者都當(dāng)成“解耦”手段混用。為什么漏兩者都涉及多個對象之間的通信解耦。怎么補觀察者是目標(biāo)直接通知所有觀察者一對多廣播中介者是同事類之間不直接通信全部通過中介者轉(zhuǎn)發(fā)多對多變成星形。5.4 簡單工廠 vs 工廠方法 vs 抽象工廠維度不同易漏點把三個工廠當(dāng)成同一維度的遞進(jìn)關(guān)系。為什么漏名字都帶“工廠”容易按復(fù)雜度排序記憶。怎么補簡單工廠是“一個工廠根據(jù)參數(shù)創(chuàng)建多種產(chǎn)品”工廠方法是“每個產(chǎn)品對應(yīng)一個工廠”抽象工廠是“每個工廠創(chuàng)建一族產(chǎn)品”。簡單工廠是工廠方法的簡化特例抽象工廠是工廠方法的多產(chǎn)品等級擴展。5.5 單例 vs 原型唯一 vs 復(fù)制易漏點認(rèn)為單例和原型都是“控制對象數(shù)量”的模式。為什么漏兩者都涉及對象創(chuàng)建的控制。怎么補單例保證全局只有一個實例原型保證可以復(fù)制出多個相同實例。單例限制數(shù)量原型提供復(fù)制機制。6. 復(fù)習(xí)清單與查漏補缺從模式選擇維度到模擬自測復(fù)習(xí)到最后一輪最有效的方式不是從頭翻資料而是拿一張模式選擇維度表做自測。下面這張表梳理了選模式時最關(guān)鍵的幾個判斷維度。判斷維度問題對應(yīng)模式對象創(chuàng)建創(chuàng)建邏輯復(fù)雜還是產(chǎn)品族工廠方法/抽象工廠/建造者接口不兼容需要轉(zhuǎn)換接口嗎適配器功能擴展需要動態(tài)添加功能嗎裝飾器訪問控制需要控制對象訪問嗎代理算法切換需要運行時切換算法嗎策略狀態(tài)驅(qū)動行為隨狀態(tài)改變嗎狀態(tài)通信解耦多對象通信太復(fù)雜中介者/觀察者請求處理需要沿鏈傳遞請求嗎責(zé)任鏈撤銷恢復(fù)需要保存和恢復(fù)狀態(tài)嗎備忘錄樹形結(jié)構(gòu)部分-整體層次組合自測方法拿一張白紙先默寫七大原則再按創(chuàng)建型、結(jié)構(gòu)型、行為型三類默寫所有模式名稱然后對每個模式寫出“一句話定義 一個適用場景 一個易混模式”。寫不出來的就是漏洞回去翻對應(yīng)章節(jié)。// 自測代碼模板用最小代碼驗證是否真正理解某個模式 // 以策略模式為例如果能不查資料寫出以下結(jié)構(gòu)說明基本掌握 interface Strategy { void execute(); } class ConcreteStrategyA implements Strategy { public void execute() { System.out.println(策略A); } } class Context { private Strategy strategy; public Context(Strategy s) { this.strategy s; } public void run() { strategy.execute(); } } // 測試切換策略驗證客戶端無需修改參數(shù)說明Context 構(gòu)造函數(shù)注入 Strategyrun() 委托執(zhí)行。如果能獨立寫出并解釋為什么這樣設(shè)計符合依賴倒轉(zhuǎn)和開放-封閉說明策略模式過關(guān)。最后一輪復(fù)習(xí)建議按這個順序走先過一遍七大原則再按三類默寫模式名稱然后重點看易混淆對比表最后用模擬題自測。我自己的習(xí)慣是每次復(fù)習(xí)設(shè)計模式都強制走一遍“原則→分類→模式→對比→自測”這條鏈路因為跳過任何一步都會在面試或?qū)嶋H選型時卡殼。最容易忽略的其實是原則和模式之間的映射關(guān)系——很多人能背出二十三種模式的名字但被問到“這個模式體現(xiàn)了哪條原則”時就答不上來而這恰恰是區(qū)分死記硬背和真正理解的分水嶺。希望這份梳理能幫到你。本文還有配套的精品資源點擊獲取