從C++編程入手設計模式——策略設計模式
? 在我們平時寫程序的過程中,經常會遇到這樣的情況:一個對象的某個功能可以有多種實現方式,而且可能會根據不同的場景切換這些方式。比如一只動物可以發出不同的叫聲,一個排序器可以使用不同的排序算法,一個支付系統可以接入不同的支付平臺。這時候,我們就可以使用“策略設計模式”。
? 策略策略,實際上就是做一個事情的策略方法。換而言之,這個設計模式用在哪些應付解決方案多變的場景。我們把某個行為(比如“怎么叫”“怎么排序”“怎么支付”)封裝成一個獨立的策略對象,讓原本需要執行這個行為的類把這個行為委托給策略對象來完成。這樣,我們可以很方便地替換行為、擴展行為,而不需要修改原來的類。
#include <iostream>
#include <functional>class Context {
public:void setStrategy(std::function<void()> strat) {strategy = strat;}void executeStrategy() {if (strategy) {strategy();}}private:std::function<void()> strategy;
};
? 如你所見,這就是把我們具體的實現行為替換成給定接口的函數指針。
策略模式的結構
從設計的角度來看,策略模式通常包含三部分:
- 策略接口:定義某個行為的抽象,比如“排序算法”或“支付方式”。
- 具體策略:不同的實現,比如“冒泡排序”、“支付寶支付”。
- 上下文類:也就是使用這些策略的地方,內部持有一個策略接口的對象,通過它來執行行為。
什么場景適合用策略模式
- 有多個算法可以選擇,比如不同的排序方法、路徑規劃算法等。
- 行為需要根據不同條件動態變化,比如不同平臺上的繪圖方式。
- 不同業務場景下執行邏輯不同,比如不同國家的稅率計算方式。
和 if-else 的區別在哪?
很多人會說:“我直接寫一堆 if-else
或 switch
不也可以嗎?”確實可以,但這樣做有兩個問題:
- 每增加一種新行為就要改動原來的代碼,不利于維護。
- 所有實現都混在一起,導致類越來越臃腫,不利于閱讀和測試。
而使用策略模式,每個行為單獨封裝起來,不但代碼更清晰,還能獨立測試每一個策略實現。
一個例子
需求:設計一個動物模擬器,支持不同動物發出不同的叫聲。使用策略模式實現動物叫聲的可變換(例如狗叫 “汪汪”,貓叫 “喵喵”)。
要求:
- 定義
ISoundStrategy
接口,有一個makeSound()
函數。 - 實現
DogSoundStrategy
、CatSoundStrategy
等具體策略類。 - 定義
Animal
類,持有一個ISoundStrategy*
。 - 允許運行時更換動物的叫聲策略。
示例輸出:
Dog: 汪汪
Cat: 喵喵
Dog changes to cat sound: 喵喵
筆者沒有嚴格的實現這個題目的要求,但是您可以參考一下:
modern-cpp-patterns-playground/Strategy/AnimalSound at main · Charliechen114514/modern-cpp-patterns-playground