【設計模式】設計模式總結 ( 七大設計原則 | 創建型模式 | 結構型模式 | 行為型模式 ) ★★★
文章目錄

一、七大設計原則
1、開閉原則
2、依賴倒置原則
3、單一職責原則
4、接口隔離原則
5、迪米特原則
6、里氏替換原則
7、合成復用原則
二、創建型模式
0、簡單工廠模式 ( 不屬于 GOF 設計模式中 )
1、工廠方法模式
2、抽象工廠模式
3、建造者模式
4、單例模式
5、原型模式
三、結構型模式
1、適配器模式
2、裝飾者模式
3、代理模式
4、外觀模式
5、橋接模式
6、組合模式
7、享元模式
四、行為型模式
1、策略模式
2、觀察者模式
3、責任鏈模式
4、備忘錄模式
5、模板方法模式
6、迭代器模式
7、中介者模式
8、命令模式
9、訪問者模式
10、解釋器模式
11、狀態模式
一、七大設計原則
1、開閉原則
【設計模式】軟件設計七大原則 ( 開閉原則 )
開閉原則 :
定義 : 一個
軟件實體
,
類 / 模塊 / 函數
, 對
擴展
開放
, 對
修改
關閉 ;
抽象與實現 : 用
抽象
構建框架
, 用
實現
擴展細節 ;
優點 : 提高 軟件系統 的
可復用性 及 可維護性 ;
開閉原則 是 面向對象 設計 中 , 最基礎的 設計原則 , 它指導我們建立穩定靈活的系統 ;
開發新功能時 , 盡量
不修改原有的代碼
, 盡量
使用擴展增加新功能 ;
實現 開閉原則 的核心思想 是面向抽象編程 , 不是面向實現編程 ;
定義的
對象類型
是
抽象類類型 或 接口類型
,
調用的方法
是
抽象類 或 接口 中的方法 ;
抽象是
穩定的
, 讓類依賴于抽象 ,
對于修改來說就是封閉的 ;
通過 面向對象 的
繼承
, 以及
多態機制
, 可以實現
對 抽象 的 繼承
, 通過
重寫改變其固有方法
, 或
實現新的擴展方法 ;
2、依賴倒置原則
【設計模式】軟件設計七大原則 ( 依賴倒置原則 | 代碼示例 )
依賴倒置原則 :
高層模塊
不應該 依賴
低層模塊
, 二者都應該
依賴其抽象
;
抽象 不應該 依賴細節 ,
細節應該依賴抽象 ;
針對接口編程 , 不要針對實現編程 ;
通過抽象 , 包括使用
接口 或 抽象類
, 使個各類或模塊之間
彼此獨立 , 互不影響
, 從而實現模塊之間的
松耦合
,
降低模塊間的耦合性 ;
使用依賴倒置原則時的注意點 :
每個類都 盡量
實現自接口
或
繼承抽象類 ;
盡量
避免從具體的類派生 ;
盡量
不要覆蓋基類方法 ;
依賴倒置原則的優點 : 減少類之間的
耦合性
, 提高系統
穩定性
, 提高
代碼可讀性
,
可維護性
, 可
降低修改程序所造成的風險 ;
3、單一職責原則
【設計模式】軟件設計七大原則 ( 單一職責原則 | 代碼示例 )
單一職責原則 : 不要存在
多余一個
導致
類變更的原因 ;
假設有一個類 , 負責 2 2 2 個職責 , 職責 1 1 1 和 職責 2 2 2 ;
一旦
需求發生變更
, 如 職責 1 1 1 相關功能發生改變 ;
修改該類的 職責 1 1 1 功能時
,
有可能導致原本運行正常的職責 2 2 2 發生故障 ;
對于上述類 , 應該
分別針對 職責 1 1 1 和 職責 2 2 2
,
各自建立一個獨立的類
, 這樣就保證了系統的穩定性 ;
這樣修改 職責 1 1 1 和 職責 2 2 2 中的任何一個功能 , 都不會影響另外一個職責的功能 ;
推薦的開發方法 : 使一個
類 / 接口 / 方法
只負責一項職責 ;
單一職責優點 : 提高
類的 可讀性
, 提高
系統的 可維護性
, 降低
類的復雜度
, 降低
變更引起的風險 ;
類越簡單
,
可讀性越好
,
同時提高了可維護性 ;
一個類只負責一個職責 , 比負責多個職責 , 類要
簡單得多 ;
變更是必然的 , 必須要接收變更 , 如果
單一職責原則遵守的好
, 當修改一個功能時 , 可以
顯著降低對其它功能的影響 ;
單一職責原則 不只是 面向對象 設計中特有的職責 , 只要是模塊化的系統 , 都適合使用單一職責原則 ;
4、接口隔離原則
【設計模式】軟件設計七大原則 ( 接口隔離原則 | 代碼示例 )
接口隔離原則 : 用
多個
專門的 接口
, 不使用
單一 的總接口
, 客戶端
不應該依賴
它
不需要的 接口 ;
一個類 對 另一個類 的依賴 , 應該建立在 最小接口 上 ; 如果 有一個
大接口
, 里面有
很多方法
, 如果使用一個類
實現該接口 ,
所有的類都要實現 ;
建立 功能 單一接口 , 不要建立 龐大 臃腫 的接口 ;
盡量細化接口 , 接口中的方法盡量少 ;
接口設計適度原則 : 接口隔離原則 中 最重要的就是 注意
適度原則
, 一定要適度 ;
接口設計的
過大 , 過小
,
都不合適
; 設計接口時 , 多花時間去思考策劃 ;
接口方法 盡量少 , 但要有限度 ,
對接口進行細化
, 肯定能
提高系統設計的靈活性
, 但是如果
接口設計的過小 , 方法過少
, 則會
造成接口數量過多 , 提高整個程序設計的復雜性 ;
接口隔離原則 優點 : 符合
高內聚
,
低耦合
的
設計思想
, 使得類具有很好的
可讀性 ,
可擴展性 ,
可維護性 ;
降低耦合 : 平時設計接口時 ,
只暴露客戶端需要的方法
, 客戶端不需要的方法 , 直接隱藏起來 ; 只有專注的為一個模塊提供定制服務 , 才能
建立最小的依賴關系
, 這樣就降低了耦合程度 ;
提高內聚 : 減少對外交互 ,
使用接口中最少的方法 ,
完成最多的事情 ;
實際開發中 , 實踐接口隔離原則時 , 也要根據業務場景 , 業務模型 , 以及以后有可能會發生變更的地方 , 對于這些做一些預判 , 抽象出業務模型很重要 ;
5、迪米特原則
【設計模式】軟件設計七大原則 ( 迪米特原則 | 代碼示例 )
迪米特原則 又稱為
迪米特法則 ,
最少知道原則 ,
最少知識原則 ;
定義 :
一個對象
應該 對
其它對象
,
保持最少的了解 ;
盡量 降低 類之間的耦合 ;
對外部引入的類 , 越少越好 ;
迪米特原則優點 :
降低了 類 之間的耦合 ;
代碼實現的層面最佳做法 : 盡量不要對外公開太多的 public 方法 , 和 public 變量 , 盡量內斂 , 多使用 private / protected 權限 ;
迪米特原則 的 核心觀念 : 就是
類 之間的解耦
, 解耦 是有一定程度的 , 盡量做到
弱耦合
,
耦合程度越低 ,
類的復用率 才能提高 ;
由于 減少了
類之間 不必要的依賴
, 從而達到了
降低了 耦合 的目的 ;
適度使用 : 使用 迪米特原則 要
適度
, 如果
過分使用迪米特原則
, 會
產生大量中介類 , 導致
系統變復雜 ,
增加維護難度 ;
使用 迪米特原則 要權衡利弊 , 既要做到
結構清晰
, 又要做到
低耦合
高內聚 ;
如果存在一個方法 , 既可以放在 A 類中 , 又可以放在 B 類中 ;
這種情況下 , 如果一個方法 可以放在本類中 , 既
不增加類間關系
, 也
沒有對本類產生負面影響
, 就可以放到本類中 ;
方法中 , 如果 參數 , 返回值 , 使用了其它類 , 導致了
import 導入了一個依賴
, 這就
增加了類間的關系 ;
迪米特原則 強調 只和朋友交流 , 不和陌生人說話 ;
這里的朋友 指的是 : 出現在
成員變量
, 方法的
輸入
,
輸出參數
中的類 , 稱為成員朋友類 , 出現在方法體內部的類 , 不屬于朋友類 ;
也就是說 類 A , 我使用了 類 A 中的方法 , 或成員 , 盡量避免導致本類 import 導入新的類 ;
6、里氏替換原則
【設計模式】軟件設計七大原則 ( 里氏替換原則 | 定義 | 定義擴展 | 引申 | 意義 | 優點 )
【設計模式】軟件設計七大原則 ( 里氏替換原則 | 代碼示例 | 類示例 | 方法入參示例 | 方法返回值示例 )
里氏替換原則定義 :
如果 對每一個
類型為 T1
的
對象 o1
, 都有
類型為 T2
的
對象 o2 ,
使得
以 T1 定義的
所有程序 P
在
所有對象 o1
都
替換成 o2 時 ,
程序 P
的
行為 沒有發生變化 ,
那么
類型 T2
是
類型 T1
的
子類型 ;
符號縮寫說明 : T 是
類型 Type
, o 是
對象 Object
, P 是
程序 Program ;
通俗理解 :
T1 類
生成
o1 對象 ,
T2 類
生成
o2 對象 ,
開發的
程序 P
中
使用了 T1 類型
,
使用 T1 創建了對象 o1 ,
將程序中
所有的 o1
都替換成
T2 o2 時 ,
程序 P 的行為 , 沒有發生變化 ,
可以認為
T2 是 T1 的子類型 ;
T2 是 T1 的子類型 , T1 則是 T2 的父類 ;
里氏替換原則 是
繼承復用
的基石 , 只有當
子類 可以 替換
父類 , 并且
軟件功能不受影響
時 ,
父類才能真正的被復用
, 子類也能在父類的基礎上
增加新的行為 ;
里氏替換原則 是對
開閉原則
的補充 , 實現開閉原則的關鍵是 進行抽象 , 父類 和 子類 的繼承關系 , 就是 抽象 的具體實現 ;
里氏替換原則引申意義 :
子類 可以
擴展
父類的功能
, 但是絕對不能
改變
父類原有的功能 ;
子類 可以
實現
父類的
抽象方法
, 但是
不能
覆蓋
父類的
非抽象方法 ;
子類中 可以
增加
自己特有的方法 ;
重載 ( 輸入參數 寬松 ) : 子類的方法
重載
父類的方法
時 , 方法的前置條件 ( 輸入參數 ) , 要比
父類方法的輸入參數更寬松 ;
如 : 父類的參數是 HashMap , 如果要符合 里氏替換原則 , 子類如果重載父類方法 , 那么需要使用 Map 類型參數 ;
( 這里注意區分 重寫 與 重載 , 重寫是重寫父類方法 , 重載是函數名相同 , 參數不同 )
重寫 ( 返回值 嚴格 ) : 當 子類的方法
重寫 / 重載 / 實現
父類的方法時 , 方法的
后置條件 ( 返回值 )
要
比父類更嚴格或相等 ;
如 : 父類的返回值是 Map , 子類的相同的方法 是 Map 或 HashMap ;
7、合成復用原則
【設計模式】軟件設計七大原則 ( 合成復用原則 | 代碼示例 )
合成復用原則
又稱為
組合復用原則
,
合成/聚合復用原則 ,
組合/聚合復用原則 ;
合成復用原則定義 : 想要達到
軟件復用
的目的 , 盡量使用
對象 組合/聚合
, 而不是
繼承關系 ;
聚合 是 has-A 關系 ; ( 關系較弱 )
代表部分事物的對象 ( 次 )
與
代表聚合事物的對象 ( 主 )
生命周期無關 , 刪除了聚合對象 , 不代表刪除了代表部分事物的對象 ;
組合 是 contains-A 關系 ; ( 關系較強 ) 一旦刪除
代表組合事物的對象 ( 主 )
, 那么
代表部分事物的對象 ( 次 )
也一起被刪除 ;
繼承 是 is-A 關系 ;
電腦 與 U 盤 是聚合關系 , 電腦沒了 , U 盤可以獨立存在 , 還可以接在其它電腦上 ;
A 類中包含了 B 類的引用 ,
當 A 類對象銷毀時
,
B 類引用所指向的對象也一同消失
, 沒有任何一個引用指向他 , 該引用成為了垃圾對象 , 被回收 ;
這種情況就是 組合 ;
加入 A 類銷毀后 ,
B 類對象還有在其它位置被引用 ,
B 類對象不會被銷毀 ,
此時這種關系就是 聚合 ;
二、創建型模式
工廠方法模式 , 抽象工廠模式 , 建造者模式 , 單例模式 , 使用頻率較高 ;
原型模式 使用頻率較低 ;
0、簡單工廠模式 ( 不屬于 GOF 設計模式中 )
【設計模式】簡單工廠模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
簡單工廠模式 : 由 一個
工廠對象
決定 創建出
哪一種
產品類
的
實例 ;
簡單工廠模式類型 : 創建型 ;
簡單工廠模式適用場景 :
創建對象少 :
工廠類
負責
創建的對象
比較少 ;
不關心創建過程 :
客戶端
只知道
傳入 工廠類 的參數
, 對于
如何創建對象
不關心 ;
簡單工廠模式優點 : 只需要傳入
正確的參數
, 就可以
獲取需要的對象
,
無需知道創建細節 ;
工廠類中有必要的
判斷邏輯
, 可以決定
根據當前的參數
創建對應的產品實例
,
客戶端可以免除直接創建產品對象的責任 ;
通過該模式 , 實現了對
創建實例
和
使用實例
的
責任分割
;
提供專門的
工廠類
用于創建對象 ,
客戶端
無需知道所創建的產品類的類名 , 只需要知道對應產品類的參數即可創建對象實例 ;
簡單工廠模式缺點 :
工廠類
職責 過重
, 如果要增加新的產品 , 需要
修改工廠類的判斷邏輯
,
違背 " 開閉原則 " ;
7 7 7 大設計原則 ,
不能全部遵守 ,
也不能不遵守 ,
注意平衡 功能 和 系統復雜度 , 找到最合適的一個點 ;
1、工廠方法模式
【設計模式】工廠方法模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
工廠方法模式 : 定義一個
創建對象
的
接口
, 讓
實現這個接口的子類
決定
實例化哪個類
, 工廠方法讓
類的實例化
推遲到子類中進行 ;
工廠方法模式類型 : 創建型 ;
創建 實例對象
過程可能會很復雜
, 有可能會
導致大量的重復代碼
, 工廠方法模式 通過 定義 一個單獨的 創建 實例對象 的方法 , 解決上述問題 ;
通過 子類 實現 這個方法 , 創建具體的 實例對象 ;
工廠方法模式適用場景 :
重復代碼 : 創建對象 需要使用
大量重復的代碼 ;
不關心創建過程 : 客戶端
不依賴 產品類
,
不關心 實例 如何被創建 , 實現等細節 ;
創建對象 : 一個類
通過其 子類
來
指定 創建哪個對象 ;
客戶端
不需要知道
具體 產品類 的 類名
, 只需要知道
所對應的工廠
即可 , 具體的產品對象 , 由對應的工廠創建 ,
客戶端只需要知道 產品 對應的 工廠 ;
工廠方法模式 利用了 面向對象 的
多態性
, 和
里式替換 原則
;
子類對象 覆蓋 父類對象 , 使 系統
更容易擴展
, 將
創建對象的過程
推遲到子類實現
, 創建對象的任務 ,
委托給 多個 工廠子類 中的某一個 ,
客戶端不需要關心是哪個 工廠子類 創建的 產品對象 ;
工廠子類 一般都是 需要的時候 ,
動態指定 ;
工廠方法模式優點 :
不關心創建細節 : 用戶 只需要
關心 所需產品 對應的工廠 ,
無需關心創建細節 ;
符合開閉原則 : 加入 新產品 ,
符合開閉原則 ,
提高可擴展性 ;
工廠方法模式 中 ,
使用 工廠類創建 產品對象
, 同時
隱藏了 具體的 產品類 被 實例化 的細節 ;
工廠方法模式缺點 :
增加復雜性 :
類的個數容易過多
,
增加系統復雜度 ;
在 添加新產品 時 ,
除了編寫 新的產品類 之外
,
還要 編寫該產品類對應的 工廠類 ;
增加難度 : 增加了系統
抽象性
和
理解難度 ;
工廠方法本身
利用了抽象
, 該模式中會
引入抽象層
, 如果要動態創建產品類 , 還要
引入反射技術 ;
設計模式 的 使用 , 要根據 實際的 業務場景 , 模型 綜合平衡考量 , 不能過分遵守設計原則 和 設計模式 ;
2、抽象工廠模式
【設計模式】抽象工廠模式 ( 簡介 | 適用場景 | 優缺點 | 產品等級結構和產品族 | 代碼示例 )
抽象工廠模式 : 提供 一個
創建
一系列
相關 或 相互依賴
對象
的接口 ;
創建目標對象時 , 只需要直到對象的抽象類型或接口類型即可 , 不需要知道具體的實現類型 ;
抽象工廠模式類型 : 創建型 ;
抽象工廠模式 可以將
一組具有同一主題
,
單獨的工廠
封裝起來
;
在使用時 ,
客戶端
創建
抽象工廠 的實現
, 使用 抽象工廠 作為接口 , 來創建這一主題的對象 ;
使用的時候 , 不需要知道
從內部 工廠方法中獲得的 對象 的具體類型
;
客戶端 只 使用這些對象的
通用接口 ;
抽象工廠模式 實現了 一組對象的
實現細節
與
使用
分離 ;
抽象工廠模式適用場景 :
忽略創建細節 : 客戶端 不關心 產品實例
如何 被創建 ,
實現等細節 ;
創建產品族 : 強調
一系列 相關的 產品對象
, 一般是
同一個產品族
,
一起使用 創建對象需要大量重復的代碼 ;
產品類庫 : 提供 一個
產品類 的庫
, 所有的產品 以
同樣的接口出現
, 使
客戶端不依賴于具體實現 ;
使用抽象工廠模式 , 可以在工廠變化時 , 不需要修改 客戶端 使用工廠的 代碼 ;
抽象工廠模式優點 :
隔離產品代碼 : 在
應用層
隔離
具體產品的代碼
, 客戶端
無須關心 產品創建 的細節 ;
創建產品族 : 將
一個系列 的 產品族 ,
統一到一起創建 ;
抽象工廠模式缺點 :
擴展困難 : 規定了 所有
可能 被創建
的
產品集合
,
產品族
中
擴展 新的產品 困難
, 需要
修改抽象工廠的接口 ;
增加難度 : 增加了系統的
抽象性
和
理解難度 ;
產品等級結構和產品族 :
下圖中 , 有 橢圓形 , 圓形 , 正方形 , 三種產品 ;
產品族 : 相同顏色的代表一個產品族 ;
產品等級結構 : 相同形狀的代表同一個產品等級結構 ;
如 : 方型 - 洗衣機 , 圓形 - 空調 , 橢圓 - 冰箱 ;
橫向 看 產品族 : 某 品牌下 有 方型 - 洗衣機 , 圓形 - 空調 , 橢圓 - 冰箱 , 這是一個產品族 ;
縱向看產品等級結構 : 橢圓 - 冰箱 , 縱向指的是不同品牌的冰箱 ;
工廠方法模式 針對的是
產品等級結構
, 可以
擴展多個相同的產品 ;
抽象工廠模式 針對的是
產品族
, 在 某個品牌 的工廠中取出 洗衣機 類 , 取出的肯定是 該品牌的洗衣機實例對象 ;
只要指出 產品所在的 產品族 以及 產品所在的 產品等級結構 , 就可以唯一確定一個產品 ;
左側的 縱坐標軸 上的 工廠 是
具體的工廠
, 從該具體的工廠中
創建的實例
是
該產品族中的實例 ;
使用 工廠模式 還是 抽象工廠模式 , 要看具體的業務場景 ;
當一個工廠 可以 創建
分屬于
不同 產品等級結構
的
一個 產品族
中的
不同對象時
, 使用
抽象工廠模式 ;
如 :
工廠 中可以創建
相同品牌的 洗衣機 , 冰箱 , 空調
等產品 , 使用 抽象工廠模式 ;
如果 工廠中創建
不同品牌的空調
, 則使用 工廠方法模式 ;
3、建造者模式
【設計模式】建造者模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
建造者模式 : 將
一個復雜對象
的
構建過程
與其
表示
分離 , 使得
同樣的構建過程
, 可以
創建不同的表示 ;
用戶只需要
指定
需要建造的類型
就可以
得到該類型對應的產品實例
, 不關心建造過程細節 ;
建造者模式就是 如何逐步構建包含多個組件的對象 ,
相同的構建過程 ,
可以創建不同的產品 ,
建造者模式類型 : 創建型 ;
建造者模式適用場景 :
結構復雜 : 對象 有
非常復雜的內部結構 ,
有很多屬性 ;
分離創建和使用 : 想把 復雜對象 的
創建
和
使用
分離 ;
當創造一個對象 需要很多步驟時 , 適合使用建造者模式 ;
當創造一個對象 只需要一個簡單的方法就可以完成 , 適合使用工廠模式 ;
建造者模式優點 :
封裝性好 :
創建
和
使用
分離 ;
擴展性好 : 建造類之間
相互獨立
, 在
一定程度上解耦 ;
建造者模式缺點 :
增加類數量 :
產生多余的 Builder 對象 ;
內部修改困難 : 如果
產品內部發生變化
, 建造者也要相應修改 ;
建造者模式 與 工廠模式 :
注重點不同 : 建造者模式 更注重于
方法的調用順序
; 工廠模式 注重于
創建產品
, 不關心方法調用的順序 ;
創建對象力度不同 : 創建對象的力度不同 ,
建造者模式可以創建復雜的產品 ,
由各種復雜的部件組成 ,
工廠模式創建出來的都是相同的實例對象 ,
4、單例模式
5、原型模式
【設計模式】原型模式 ( 概念簡介 | 使用場景 | 優缺點 | 基本用法 )
【設計模式】原型模式 ( 淺拷貝 | 深拷貝 | 原型與單例沖突 | 禁用 final )
原型模式 :
用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象
① 設計模式類型 :
創建型設計模式 ;
② 原型實例對象 :
給出原型實例對象 , 根據該對象創建新對象 ;
③ 創建對象類型 :
創建對象的種類由原型的實例對象類型確定 ;
④ 創建方式 :
不調用構造函數 , 而是通過克隆原型的實例對象 , 使用現有對象創建另一個相同類型的對象 , 隱藏創建細節 ;
原型模式使用場景 :
原型模式的目的是
降低實例對象個數 , 減少構造函數的調用次數 ;
① 類初始化消耗資源過多 :
如果類初始化時消耗過多的資源 , 如這個類中某個成員占用大量內存 , 為了節省開銷 ;
② 初始化繁瑣耗時 :
類對象創建時經過大量的計算 , 或與本地資源 ( 數據庫 , 文件 ) 頻繁交互 , 每次創建消耗大量的 CPU 與 時間資源 ;
③ 構造函數復雜 :
類中定義的構造函數復雜 ;
④ 實例對象數量龐大 :
如果在內存中循環創建了很多該實例對象 , 就可以使用原型模式復用不用的對象 , 用于創建新對象 ;
1 . 原型模式優點 :
性能高 , 簡單 ;
① 性能高 :
使用原型模式復用的方式創建實例對象 , 比使用構造函數重新創建對象性能要高 ;
( 針對類實例對象開銷大的情況 )
② 流程簡單 :
原型模式可以簡化創建的過程 , 可以直接修改現有的對象實例的值 , 達到復用的目的 ;
( 針對構造函數繁瑣的情況 )
2 . 原型模式缺點 :
實現復雜 , 坑多 ;
① 覆蓋 clone 方法 ( 必須 ) :
必須重寫對象的 clone 方法 , Java 中提供了 cloneable 標識該對象可以被拷貝 , 但是必須覆蓋 Object 的 clone 方法才能被拷貝 ;
② 深拷貝 與 淺拷貝 風險 :
克隆對象時進行的一些修改 , 容易出錯 ;
需要靈活運用深拷貝與淺拷貝操作 ;
三、結構型模式
適配器模式 , 裝飾者模式 , 代理模式 , 外觀模式 , 橋接模式 , 享元模式 使用較頻繁 ;
組合模式不經常使用 ;
1、適配器模式
【設計模式】適配器模式 ( 概念 | 適用場景 | 優缺點 | 外觀模式對比 | 適配器模式相關角色 | 類適配器 | 對象適配器 | 實現流程 )
適配器模式 :
① 設計模式類型 :
結構型 ;
② 概念 :
將 類的接口 轉換成用戶可以調用的 另外一個接口 ;
③ 目的 :
使接口不兼容的兩個類可以一起工作 ;
④ 概念中的三個角色 :
被適配者 ( 現有的功能類 ) ,
用戶目標接口 ( 用戶調用的接口 ) ,
適配器類 ( 用戶通過調用該類 , 間接調用 被適配者類 ) ;
⑤ 簡易原理 :
適配器類 實現用戶目標接口 ,
在該接口的實現類中調用被適配者 , 實現了接口轉接的效果 ;
使用的時候 , 通過創建適配器類 , 即可間接調用被適配者方法 ;
適配器模式 適用場景 :
1 . 功能正確但接口不匹配 :
對于之前開發好的類 , 該類的操作和返回值都是正確的 , 但是其定義的方法接口無法調用 ,
此時使用適配器模式 , 使該類與用戶的接口匹配 , 讓用戶使用適配器的接口 , 間接調用該類 ;
2 . 適配器模式使用階段 :
軟件設計開發階段一般不使用適配器模式 , 在軟件維護時 , 出現操作和返回值類似 , 但是函數接口不同 , 為了適配第三方系統的接口 , 使用適配器模式 ;
設計階段不要使用適配器模式 ;
3 . 適配器的兩種實現方式 : 對象適配器模式 與 類適配器 ;
① 對象適配器 :
符合組合復用原則 , 使用了委托機制 ; ( 通過組合實現 , 適配器類中維護被適配者成員 )
② 類適配器 :
通過類的繼承實現適配器模式 ; ( 通過繼承實現 , 適配器類繼承被適配者類 )
推薦使用對象適配器模式 , 在繼承與組合二者之間 , 優先選擇組合方案 ;
1 . 適配器模式 優點 :
① 復用且不修改類 :
不改變現有類的基礎上 , 提高類的復用性 , 透明性 ; 讓現有類與目標類接口匹配 ;
② 降低耦合 :
目標類 ( 用戶調用的接口所在類 ) 和 現有類 ( 被適配者 ) 解除耦合 , 降低了系統的耦合性 , 易于擴展維護 ;
③ 符合開閉原則 :
用戶調用適配器接口 , 只與適配器類進行交互 , 如果需要修改擴展 , 只需要修改適配器類即可 , 目標類 和 現有類 各自都是相互獨立的 , 互不影響 ;
2 . 適配器模式 優點 :
① 增加復雜性 :
編寫適配器類時 , 需要考慮全面 , 包括被適配者 和 目標類 , 系統復雜性會增加 ;
② 降低可讀性 :
系統代碼可讀性降低 , 可維護性降低 ;
閱讀代碼時 , 調用系統接口 , 如果調用的是適配器接口 , 還要到處找調用的是哪個現有類的實際接口 ;
適配器模式 與 外觀模式對比 :
1 . 相同點 :
都是對現有類進行封裝 ;
2 . 行為分析 :
① 外觀模式行為 :
外觀模式定義了新街口 , 處理多個子系統之間的交互 ;
② 適配器模式行為 :
適配器模式復用原有接口 , 只是簡單的轉接了一下 , 使兩個現存接口 ( 現有類 和 目標類 ) 協同工作 ;
3 . 適配力度分析 :
① 外觀模式 :
適配力度很大 , 需要開發整個子系統之間的交互流程 ;
② 適配器模式 :
修改很少的內容 , 只是進行簡單的接口轉接交互 , 一般不實現具體的功能 ;
適配器模式 相關角色 ( 重點 )
1 . 被適配者 :
實際功能提供者 , 是系統中原有的類 ;
2 . 用戶目標接口 :
用戶調用該接口 , 實現功能操作 ; 是適配器的父類接口 ;
3 . 適配器 :
需要實現 用戶目標接口 , 并在接口中的操作中 , 調用被適配者提供的實際功能 ;
適配器有兩種途徑實現 , 分別是類適配器 , 對象適配器 ;
① 類適配器 :
繼承被適配者 , 通過 super 訪問被適配者方法 ;
② 對象適配器 ( 推薦 ) :
在適配器中維護一個被適配者成員變量 , 通過成員變量訪問被適配者方法 ;
適配器模式 ( 對象適配器 ) 代碼實現流程 ( 重點 )
1 . 明確被適配者 :
被適配者 是一個現有類 , 該類保持不變 ;
2 . 定義用戶目標接口 :
用戶通過調用該接口 , 實現實際的功能 ,
該功能與適配者中的功能類似 , 但 接口不同 ;
3 . 聲明適配器 :
① 適配器 實現 用戶目標接口 :
適配器 需要實現 用戶目標接口 ,
在實現的接口方法中 , 需要將實際操作 委托給 被適配者 ;
② 適配器 維護 被適配者 類型成員變量 :
如何調用到 被適配者 的方法呢 ,
這里 適配器 通過 定義 被適配者 類型的成員變量 ,
通過該 被適配者 類型成員變量 , 調用 被適配者 public 方法 ;
③ 委托操作 :
在實現的 用戶目標接口中 ,
通過 被適配者類型 成員變量 , 調用 被適配者 的方法實現具體功能 ;
類適配器
與
對象適配器 ,
本質區別就是 適配器類訪問 被適配者的途徑 ;
類適配器 :
通過繼承 被適配器 , 獲取訪問被適配器方法的資格 ;
對象適配器 :
通過在其內部維護一個 被適配者 成員變量 , 進而通過該成員變量訪問 被適配者方法 ;
4 . 用戶訪問操作 :
① 定義目標接口變量 :
定義 用戶目標接口 對象變量 ;
② 目標接口變量賦值 :
創建 適配器對象 賦值給上述 用戶目標接口對象變量 , ( 適配器 是 用戶目標接口 的子類 ) ;
③ 目標接口調用 :
調用用戶目標接口 , 即可調用被適配者的實際功能方法 ;
2、裝飾者模式
【設計模式】裝飾者模式 ( 概念 | 適用場景 | 優缺點 | 與繼承對比 | 定義流程 | 運行機制 | 案例分析 )
裝飾者模式概念 :
① 設計模式類型 :
結構性 ;
② 概念 :
不改變原有類的對象 , 動態地將額外的功能附加到該對象上 ;
③ 擴展對象功能 :
這種功能擴展方式比類繼承更加靈活 ;
④ 裝飾者模式 :
移除類中的被裝飾功能 , 將被裝飾類簡化 , 區分類的核心職責 和 裝飾功能 ;
裝飾者模式適用場景 :
① 功能擴展 :
為一個類擴展功能 , 為其添加額外的職責 ;
( 強調擴展 )
② 動態添加撤銷功能 :
為一個對象動態添加額外功能 , 同時這些被添加的功能還能被動態撤銷 ;
( 強調動態 )
裝飾者模式優點 :
① 擴展靈活 :
使用裝飾者模式 , 比繼承更加靈活 ; 使用裝飾者模式擴展類功能 , 不會改變原來的類 ;
② 排列組合 :
對裝飾類進行各種排列組合 , 可實現不同的擴展功能 ;
③ 開閉原則 :
裝飾者模式符合開閉原則 , 被裝飾的類 , 和裝飾類相互獨立 , 互不干擾 ;
裝飾者模式缺點 :
① 程序復雜 :
需要編寫更多的代碼 , 生成更多的類 , 程序的復雜性增加了 ;
② 動態 / 多層 裝飾 :
動態 / 多層 裝飾一個類時 , 程序更復雜 ;
3、代理模式
【設計模式】代理模式 ( 簡介 | 適用場景 | 優缺點 | 代理擴展 | 相關設計模式 )
【設計模式】代理模式 ( 靜態代理 )
【設計模式】代理模式 ( 動態代理 )
代理模式 : 為
其它對象
提供
一種代理
, 以
控制
對
這個對象
的訪問 ;
代理對象
在
客戶端
和
目標對象
之間 起到
中介的作用 ;
如 : 租客通過中介找房東租房子 , 房東將房子托管給了中介 ,
房東是目標對象
, 但是租賃行為是中介來執行的 ,
中介是代理類
,
租客 就是 客戶端 ;
中介
代理
房東
進行租賃行為 , 相當于
代理類對目標對象進行了增強 ;
客戶端 通過 代理類 與 目標對象 進行交互 , 客戶端 不直接接觸 目標對象 ;
代理模式類型 : 結構性 ;
代理模式適用場景 :
保護目標對象 :
客戶端
只與
代理類
進行交互 , 不清楚
目標對象
的具體細節 ; 相當于 租客 只與 中介 進行交互 , 不知道房東的信息 ;
增強目標對象 : 代理類 在 目標對象的基礎上 ,
對 目標對象的功能 進行增強 ;
代理模式優點 :
分離目標對象 : 代理模式 能將
代理對象
與 真實被調用的
目標對象
分離 ;
降低耦合 : 在一定程度上 ,
降低了系統耦合性
, 擴展性好 ;
保護目標對象 : 代理類 代理目標對象的業務邏輯 ,
客戶端
直接與
代理類
進行交互 ,
客戶端 與 實際的目標對象之間沒有關聯 ;
增強目標對象 : 代理類 可以 在 目標對象基礎上 ,
添加新的功能 ;
代理模式缺點 :
類個數增加 : 代理模式 會 造成 系統中
類的個數 增加
, 比不使用代理模式增加了代理類 ,
系統的復雜度增加
; ( 所有的設計模式都有這個缺點 )
性能降低 : 在 客戶端 和 目標對象 之間 ,
增加了一個代理對象 ,
造成 請求處理速度變慢 ;
靜態代理 : 在代碼中 ,
使用指定的代理
; 顯示的定義了一個業務實現類代理 ; 在代理類中 , 對同名的業務方法進行包裝 , 用戶通過調用 代理類中 被包裝過的業務邏輯方法 , 來調用 被包裝對象 的業務方法 , 同時對目標對象的業務方法進行增強 ;
動態代理 : 由 JDK 提供 , 只能對
實現的接口的類
進行動態代理 ,
不能代理具體的實現類
; 通過
接口
中的
方法名
, 在
動態生成的 代理類
中 , 調用
業務實現類
的
同名方法 ;
JDK 動態代理 , 用到的代理類 , 是在程序調
用到代理對象時
,
由 Java 虛擬機創建
, Java 虛擬機 根據傳入的
業務實現類對象
以及
方法名
,
動態地創建代理類 Class 文件
,
當該 Class 文件被字節碼引擎執行
,
通過該代理類對象進行目標方法的調用 ;
動態代理無法代理類 , 只可以代理接口 ;
CGLib 代理 : 可以
針對類實現進行代理
;
如果要
代理一個類
,
CGLib 會生成一個被代理類的子類
, 通過
繼承該類
并
覆蓋其中的方法
;
如果該類時 final 的 , 則無法被繼承 , 如果類中的方法是 final 的 , 該方法無法被重寫 ;
使用 CGLib 代理要特別注意 final 修飾符 ;
4、外觀模式
【設計模式】外觀模式 ( 概念 | 適用場景 | 優缺點 | 代碼示例 )
1 . 外觀模式概念 :
① 設計模式類型 :
結構型 ;
② 標準定義 :
提供一個統一接口 , 用于訪問子系統中的一群接口 ;
③ 隱藏復雜性目的 :
定義高層級接口 , 讓子系統更容易使用 , 目的是隱藏系統的復雜性 ;
④ 交互流程 :
多個子系統聯合完成一個操作 , 提供一個統一的接口 , 供客戶端調用 , 客戶端不與每個子系統進行復雜的交互 , 客戶端只與提供接口的外觀類進行交互 ;
2 . 外觀模式的相關角色 :
① 外觀角色 :
外觀類有自己的方法 , 用戶可以通過調用外觀類的方法 , 調用子系統提供的功能 ;
② 子系統角色 :
可以是若干個處理模塊 , 數量 1 個或多個 ;
③ 用戶角色 :
用戶通過外觀類調用子系統的功能 ;
外觀模式適用場景 :
① 子系統復雜 :
子系統復雜 , 通過使用外觀模式可以簡化調用接口 ;
② 層次復雜 :
系統結構層次復雜 , 每個層級都一個使用外觀對象作為該層入口 , 可以簡化層次間的調用接口 ;
5、橋接模式
【設計模式】橋接模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
橋接模式 :
分離抽象實現 : 將
抽象部分
與 它的
具體實現部分
分離 , 使它們 都可以
獨立的 變化
; 獨立的變化 就是
在一定程度上 進行解耦 ;
組合方式 : 通過
組合
的方式 建立
兩個類 之間的聯系
, 而
不是 繼承 ;
橋接模式類型 : 結構型 ;
橋接模式 相當于
使用橋梁 將兩側連接起來
, 這里指的是 使用橋梁
連接兩個類
, 在兩個類之間建立某種聯系 , 可以通過繼承 , 也可以通過組合 , 橋接模式 是采用
組合的方式
, 建立兩個類之間的關系 ;
合成復用原則
,
推薦優先使用組合
, 不是繼承 ; 橋接模式
可以防止子類過多
, 造成系統復雜的情況 ;
橋接模式的重點 是 理解 類的 抽象部分 和 具體的實現部分 ;
抽象過程 :
抽象部分
, 經過
抽象化
,
忽略某些信息
, 將不同的實體當做同一個對待 ; 面向對象中 ,
將對象的共同性質抽取出來 ,
形成類的過程 ,
就是抽象化過程 ;
實現過程 : 對于具體實現的部分 , 也要進行實現化 ,
針對抽象化
,
給出具體實現
; 這個過程就是實現過程 , 過程的產出就是具體實現部分 , 具體實現部分產生的對象 , 比抽象產生的更具體 , 是對抽象化事物的具體化產物 ;
如 : 開發跨平臺的視頻播放器 , 平臺有 Android , iOS , Windows , Linux , Mac , 播放器支持的格式有 MP4 , AVI , RMVB , FLV 格式 ; 這種情況下 , 適合使用橋接模式 ;
橋接模式適用場景 :
抽象實現靈活 :
抽象
和
具體實現
之間 , 需要
增加更多靈活性
的情況下 , 適合使用橋接模式 ;
使用 橋接模式 , 可以
避免在這兩個層次之間
,
建立靜態的繼承關系
, 通過 橋接模式 在二者之間建立 關聯關系 ;
抽象 和 實現 都可以
各自 以繼承的方式擴展
,
互不影響 ;
可以動態的 將
抽象 的子類對象
和
實現 的子類對象
進行組合 , 在系統中 ,
抽象 和 實現 之間進行了解耦 ;
獨立變化維度 : 一個類存在
2 2 2 個或更多的
獨立變化維度
, 并且這些維度都需要
獨立擴展 ;
抽象部分可以 獨立擴展 , 具體實現的部分 , 也可以獨立擴展 ;
不使用繼承 : 不希望使用繼承 , 或 因多層繼承導致系統類的個數增加 ;
6、組合模式
【設計模式】組合模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
組合模式 : 將
對象
組合成
樹形結構
, 表示 "
部分-整體
" 層次結構 ;
組合模式 使
客戶端
對
單個對象
和
組合對象
保持一致的 方式處理 ;
如 : 文件系統 , 根目錄下有若干文件和目錄 , 在二級目錄下還有目錄和文件 , 這種情況下 , 適合使用組合模式 ;
組合模式類型 : 結構型
組合模式適用場景 :
忽略差異 : 希望
客戶端
可以 忽略
組合對象
與
單個對象
的差異 ;
處理樹形結構 ;
7、享元模式
【設計模式】享元模式 簡介 ( 定義 | 對象池 | 內部狀態 | 外部狀態 | 適用場景 | 相關角色 )
【設計模式】享元模式 實現 ( 實現流程 | 抽象享元類 | 具體享元類 | 享元工廠 | 用戶調用 | 代碼模板 )
1 . 享元模式 簡介 :
享元模式的核心是
對象池 ,
使用對象時 , 先從對象池中獲取對象 ,
如果對象池中沒有 , 創建一個 , 放入對象池 , 然后再從對象池中獲取 ;
( 只能從對象池中拿對象 , 不能自己創建 )
① 設計模式類型 :
結構性 ;
② 享元模式 概念 :
通過減少創建對象數量 , 改善應用中使用對象的結構 , 使用
共享對象 ( 對象池中的對象 )
, 支持多個
細粒度對象 ( 使用時的大量對象 ) ;
③ 好處 :
減少創建對象的數量 , 從而減少內存的占用 , 提高性能 ;
2 . 細粒度對象 和 共享對象 :
目的是為了提高程序性能 ;
① 細粒度對象 :
是內存中的數量龐大的對象 ;
實際使用的數量龐大的對象 ;
② 共享對象 :
多個細粒度對象共享的部分數據 ;
對象緩存池中存儲的對象 ;
③ 舉例說明 :
使用字符串值 “abc” ,
首次使用 , 創建該字符串 , 將其放入字符串緩存池中 , 這個緩存池中的字符串就是
"共享對象" ,
應用中要大量使用 “abc” 字符串 , 比如使用 10 萬個 “abc” 字符串對象 , 這 10 萬個字符串對象就是
"細粒度對象" ,
此時肯定不會創建這么多對象 , 這 10 萬個對象使用時從字符串緩存池中查找緩存的那個
"共享對象"
即可 , 這樣節省了很大的內存開銷 ;
3 . 享元模式示例 :
Java 的 String 類型就是用了享元模式的設計模式 ;
① 定義字符串 : String str = "Hello" ;
② 內存中已有該字符串 :
如果之前已經有該字符串 , 就直接將字符串緩存池中的字符串返回 ,
③ 新字符串 :
如果內存中沒有該字符串 , 就創建一個新的字符串 , 放入緩存池中 ;
享元模式就是池技術 , 如字符串池 , 數據庫連接池 等 ;
使用對象時 , 先從池中查找 , 沒有找到再創建該對象 , 然后放入對象池中 ;
4 . 享元模式使用策略 :
用戶想要調用一個對象 , 去對象池中查找 , 如果對象池中有該對象 , 那么直接使用該對象 , 如果沒有 , 創建該對象 , 放入對象池中 , 然后再從對象池中獲取該對象 ;
對象對比 :
這里涉及到一個問題 , 如何確定對象池中的對象是不是用戶想要使用的對象呢 ?
5 . 引入 內部狀態 和 外部狀態 :
對象對比問題引出這兩個概念 , 對象中有很多數據 , 那么使用什么數據來確定兩個對象是否一致呢 , 這里使用 對象的 外部狀態 來確定 ;
① 內部狀態 :
對象的內部狀態不能作為對象對比的依據 , 所有對象的內部狀態都是一樣的數據 ;
② 外部狀態 :
對象的外部狀態每個都不一樣 , 每個對象都有一個唯一 外部狀態 值 , 類似于 身份證 , 哈希碼 這一類的信息 ;
③ 身份標識 :
在線程池中 , 使用外部狀態信息 , 唯一確定一個對象 , 作為對象的標識信息 ;
1 . 概念引入 :
區分這兩個概念的目的是為了維護享元模式的對象池 , 當用戶想要使用某個對象時 , 如何確定對象池中的對象是否是用戶想要調用的對象呢 , 這里就需要一些數據進行對比 , 數據一致 , 就說明是用戶想要的對象 , 數據不一致 , 就需要創建新對象 , 放入對象池 ;
① 內部狀態 :
有些數據所有的對象都一樣 , 顯然不能當做對象一致性對比的依據 , 這就是 內部狀態 ;
② 外部狀態 :
有些數據每個對象都不一樣 , 根據該數據確定對象的唯一性 , 相當于 哈希碼 , 身份證號 , 檔案編號 這一類的數據 , 這就是外部狀態 ;
內部狀態 和 外部狀態 本質是 信息數據
2 . 內部狀態 ( 共享信息 ) :
在享元模式中的對象中 , 不隨環境改變而改變的信息 ;
① 共享信息 :
內部狀態就是可以被共享的信息 ;
② 存儲位置 :
該信息存儲在享元對象內部 ;
③ 存儲形式 :
該信息作為對象的附加數據 , 不在具體的對象中存儲 , 可以被多個對象共享 ;
3 . 外部狀態 ( 不可共享信息 ) :
隨著外部環境改變 , 對象內部跟著改變 , 這部分內容就不能進行共享 ;
不可共享 :
外部狀態不可被共享 , 每個值都必須在不同的對象中維護 ;
1 . 享元模式 適用場景 :
① 底層開發 :
某個系統的底層開發 , 對性能要求比較高 , 可使用享元模式 ;
② 緩沖池 :
系統中實例對象數量龐大 , 需要緩沖池處理這些對象 ;
2 . 享元模式使用前提 :
系統中存在大量的對象 , 這些對象狀態大部分功能可以外部化 , 將這些功能抽離出來 , 只在內存中保留一份 ;
① 分離對象功能 :
系統中如果內存中持有大量對象 , 可能會溢出 , 將這些對象相同的部分分離出來 ;
② 用戶調用行為 :
如果有相同的業務請求 , 則優先使用內存中已有的對象進行處理 , 避免使用大量相同的對象 ;
③ 注意 :
這里只有在內存中有大量相同對象時 , 才考慮享元模式 , 如果內存中某類型的對象數量較少 , 沒有必要使用該模式 ;
四、行為型模式
1、策略模式
【設計模式】策略模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
策略模式 : 定義了
算法家族
, 分別
封裝起來
, 讓它們之間 , 可以
相互替換
, 此模式 讓
算法的變化
不會影響到 使用算法的用戶 ;
將
不同的算法
, 封裝到
不同的類
中 , 讓它們之間可以
相互替換
,
使用算法的用戶 即 應用層 , 感知不到 算法已經被替換了 ;
實際的業務場景 :
不同業務邏輯 : 商品促銷 , 促銷策略 , 不同的促銷策略算法 , 封裝到不同的類中 ;
代碼優化 : 如果代碼中 , 有大量的 if … else … 代碼 , 可以通過策略模式 , 替換相關邏輯 ;
策略模式類型 : 行為型 ;
策略模式適用場景 :
行為切換 : 系統有
很多類
, 這些類的區別僅僅在于它們的
行為不同
; 使用策略模式 , 可以
動態地
讓
用戶對象
在這些行為中,
選擇一個行為
;
將對象的
不同的行為
, 封裝到
不同的類
中 ,
每個行為對應一種策略 ;
算法選擇 : 系統中需要
動態地
在
幾種算法
中
選擇一種
;
算法 就是 策略 ,
其中封裝了一系列的業務邏輯及計算方式 ;
如 : 計算方式 , 給定兩個數字 ; 使用加法策略 , 將兩個數相加 ; 使用乘法策略 , 將兩個數相乘 ;
2、觀察者模式
【設計模式】觀察者模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
觀察者模式 : 定義了
對象之間
一對多
的 依賴 , 令 多個
觀察者
對象 同時 監聽 某一個
主題對象
, 當
主題對象
發生改變時 , 所有的
觀察者
都會
收到通知 并更新 ;
觀察者
有多個 , 被觀察的
主題對象
只有一個 ;
如 : 在購物網站 , 多個用戶關注某商品后 , 當商品降價時 , 就會自動通知關注該商品的用戶 ;
主題對象 : 商品是主題對象 ;
觀察者 : 用戶是觀察者 ;
觀察者注冊 : 用戶關注 , 相當于注冊觀察者 ;
通知觸發條件 : 商品降價 ;
觀察者模式 類型 : 行為型 ;
觀察者模式適用場景 :
關聯行為
場景 , 建立一套
觸發機制 ;
如 : 用戶關注某個商品的價格 , 降價時進行通知 , 這樣
用戶
和
商品
產生了關聯 , 觸發機制就是
商品降價 ,
3、責任鏈模式
【設計模式】責任鏈模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
責任鏈模式
, 又稱為
職責鏈模式 ;
責任鏈模式定義 : 為
請求
創建一個接收該
請求對象
的
鏈
, 鏈條中每個元素都是一個對象 ;
責任鏈模式類型 :
行為型 ;
責任鏈模式 適用場景 : 一個
請求
的
處理
, 需
要多個對象
中的
一個或若干個對象
協作進行處理 ;
責任鏈模式 優點 :
① 解耦 : 請求的
發送者
和
接收者
解耦 ; 接收者 是
請求的處理者 ;
② 動態組合 : 責任鏈 可以
動態組合
, 使用配置 設置責任鏈的
順序
及
是否出現
; 可以隨時對責任鏈排序 , 隨時增加拆除責任鏈中的某個請求對象 ;
責任鏈模式 缺點 :
① 性能 : 如果 責任鏈
太長
, 或責任鏈中請求的
處理時間過長
, 可能會
影響性能 ;
② 個數 : 責任鏈
可能過多 ;
責任鏈模式 與 狀態模式 比較 :
在
責任鏈模式
中 , 并
不指定
下一個處理的 請求對象 是哪個
; 責任鏈 中 鏈條順序 可以
任意組合排序 ;
在
狀態模式
中 , 需要讓
每個 狀態
知道下一個需要處理的狀態是誰 ;
4、備忘錄模式
【設計模式】備忘錄模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
備忘錄模式 : 保存
對象
的
某個狀態
, 以便在 適當的時候
恢復對象
;
( 形象的比喻 : " 后悔藥 " )
如 : 游戲存檔 , 一些編輯工具中的 "
撤銷
" 操作 , 瀏覽器中的
后退 ;
備忘錄模式 類型 : 行為型 ;
備忘錄模式 適用場景 :
撤銷操作 :
保存 / 恢復 數據
的相關業務場景 ;
如 : 在 Word 中編寫文檔 , 如果想要撤銷之前的 輸入 / 刪除操作 , 使用 Ctrl + Z 執行 " 撤銷 " 操作 ;
狀態恢復 : 在 " 后悔 " 的時候 ,
將對象恢復到之前的狀態 ;
如 : 游戲中的存檔使用 ;
5、模板方法模式
【設計模式】模板方法模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
模板方法模式 : 定義了一個
算法
的
骨架
, 并允許 子類 為 一個或多個 步驟
提供實現 ;
模板方法模式 可以使
子類
在不改變
算法結構
的前提下 ,
重新定義算法的某些步驟 ;
模板方法模式類型 : 行為型 ;
模板方法模式適用場景 :
父類視角 : 一次性 實現 一個算法
不變的部分
, 并將
可變部分
留給
子類 實現 ;
子類視角 : 各個子類中 ,
公共部分 被提取出來 ,
集中到一個公共的父類中 ,
避免代碼重復 ;
模板方法模式的目的是 讓
子類可以擴展
或
具體實現固定方法的某個具體的步驟
; 對于模板來說 , 是一套固定的算法 , 通過子類 可以擴展 固定算法中某些算法步驟 ;
6、迭代器模式
【設計模式】迭代器模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
迭代器模式 : 提供一種方法 ,
順序訪問
集合對象
中的
各個元素
, 而
不暴露 該對象 的內部表示 ;
迭代器模式類型 : 行為型 ;
迭代器模式適用場景 :
內容保密 : 訪問
集合對象
的內容 ,
無需暴露內部表示 ;
統一接口 : 為遍歷 不同的 集合結構 ,
提供統一接口 ;
迭代器模式優點 :
分離
了 集合對象 的
遍歷行為
; 抽象出了
迭代器
負責
集合對象的遍歷
, 可以讓外部的代碼
透明的
訪問集合內部的數據 ;
迭代器模式缺點 :
類的個數成對增加
; 迭代器模式 , 將
存儲數據
,
遍歷數據
兩個職責拆分 ; 如果新添加一個
集合類
, 需要增加該 集合類 對應的
迭代器類
, 類的個數成對增加 , 在一定程度上 ,
增加了系統復雜性 ;
7、中介者模式
【設計模式】中介者模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
中介者模式 : 定義 一個
封裝一組對象
如何
交互
的
對象 ;
通過使
對象
明確地
相互引用
, 促進
松散耦合
, 允許
獨立改變
它們之間的
交互 ;
中介者模式類型 : 行為型 ;
中介者模式適用場景 :
引用關系復雜 : 系統中
對象之間
存在
復雜的 引用關系
, 產生的
相互依賴關系
結構混亂
,
難以理解 ;
改變行為 : 交互的
公共行為
, 如果 需要
改變行為
, 可以
增加新的 中介者 類 ;
( 通過增加新的中介者類 , 達到擴展的目的 )
多人聊天室 就是一個 中介者模式 場景 , 一個人發言時 , 需要傳達給每個人 , 如果沒有聊天室 , 需要對每個人都說一遍 , 如果有中介者 , 就由中介者負責將發言傳達給每個人 ;
中介者模式優點 :
降低復雜度 : 將
一對多
轉化為
一對一
,
降低了 程序復雜程度 ;
如 : 聊天室中有 8 8 8 個人 , 如果要一對一進行交互 , 需要交互 7 7 7 次 ; 使用了中介者模式后 , 變成一對一 , 只要將交互內容交給中介者就可以了 , 中介者負責與其余 7 7 7 人進行交互 ;
解耦 : 實現了
類之間的解耦 操作 ;
如 : 聊天室中有 8 8 8 個人 , 每個人都需要耦合另外 7 7 7 個 , 即持有另外 7 7 7 個對象 , 使用了中介者模式之后 , 8 8 8 個人只需要持有 中介者 對象即可 , 8 8 8 個人之間不再進行相互耦合 ;
中介者模式缺點 : 如果在 業務場景 中
中介者 數量過多
, 會導致系統
復雜性增加 ;
( 設計模式之間 , 也是一個相互平衡的過程 )
8、命令模式
【設計模式】命令模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
命令模式 : 將
不同的請求
封裝成
不同的請求對象
, 以便
使用 不同的 請求
; 對于接收者來說 , 可以識別 不同的 請求對象類型 , 然后執行 不同的操作 ;
命令模式 , 解決了 應用程序 中 ,
對象的職責
(
發送請求
/
執行請求
) , 以及它們之間的
通信方式 ;
命令模式 可以使 命令的
發送者
和
接收者
完全解耦
; 發送者 和 接收者 之間 , 并沒有直接的關系 , 二者靠
命令
進行交互 ;
命令發送者
只需要知道發送 請求對象 , 不需要知道如何完成請求 ;
命令執行者
只需要知道如何 完成請求 , 不需要知道請求的發送過程 ;
命令模式類型 : 行為型 ;
命令模式 適用場景 :
解耦發送者與接收者 :
請求發送者
和
請求接收者 ( 執行者 )
需要
解耦
, 發送者 與 接收者 之間
不直接進行交互 ;
抽象行為 : 需要將
等待執行
的行為
抽象出來 ;
9、訪問者模式
【設計模式】訪問者模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
訪問者模式 :
封裝
作用于 某種 數據結構 的 各元素
操作
, 數據結構指的是 List , Set , Map 等 ;
在
不改變 元素類
的前提下 , 定義
作用于 元素 的操作 ;
訪問者模式類型 :
行為型 ;
訪問者模式 適用場景 :
List , Set , Map 等 數據結構 中 , 包含
很多類型的對象 ;
數據結構 與 數據操作
分離 ;
10、解釋器模式
【設計模式】解釋器模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
解釋器模式 : 給定一個
語言
, 定義它的
文法
的一種表示 , 并定義一個
解釋器
, 這個 解釋器 使用該表示來
解釋 語言中的 句子 ;
文法
可以理解成一種
語法 ;
為了解釋一種語言 , 而為語言創建的
解釋器 ;
如 : Java 代碼 , 需要編譯器進行編譯之后才能運行 , 這個編譯器就相當于解釋器 ;
解釋器模式類型 : 行為型 ;
解釋器模式適用場景 : 某個
特定類型問題
發生頻率
足夠高 ;
日志處理 : 使用 腳本語言 或 編程語言 處理日志時 , 有很多服務 會產生 大量的日志 , 需要
對日志進行解析 , 生成報表 ;
各個服務的日志格式不同 , 數據中的要素相同 , 這種情況下 , 通過程序解決上述問題 , 主要的解決方案就是使用解釋器模式 ;
日常項目中 , 解釋器模式使用情況很少 ;
解釋器一般是 開源包 , 如 Express4J , JEP ;
11、狀態模式
【設計模式】狀態模式 ( 簡介 | 適用場景 | 優缺點 | 代碼示例 )
狀態模式 : 允許 對象 在
內部狀態 改變時 ,
改變它的行為 ;
一個對象 , 如果其
內部狀態改變
, 其
行為也需要進行改變
; 如果其行為不需要改變 , 也可以只
控制 該對象的狀態 的 互相轉換 ;
當控制一個對象 , 其狀態轉換過程比較復雜時 , 將
狀態判斷邏輯 ,
轉到代表不同狀態的一系列類中 ;
如 : 引入 視頻播放 的業務場景 , 播放器有 初始狀態 , 播放狀態 , 暫停狀態 , 停止狀態 , 快進狀態 等多種狀態 , 將這些
狀態
都封裝到
代表不同狀態的類
中 , 可以將復雜的判斷邏輯簡化 , 將這些
邏輯
擴展到不同的狀態類中 ;
狀態模式類型 : 行為型 ;
狀態模式適用場景 : 一個對象 ,
存在多個狀態 ,
狀態可以相互轉換 ;
不同狀態下 ,
行為不同 ;
不同狀態下 , 行為不同的示例 , 如 :
購買物品 , 將物品放入購物車并生成訂單 , 可以進行付款 ; 如果 訂單 超過 24 小時后 , 被關閉訂單 , 此時訂單取消 , 無法付款 ;
電梯運行時 , 不能開門 ; 電梯停止后 , 才能開門 ;
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。