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