使用模板參數(shù)傳入策略類型可實(shí)現(xiàn)完全靜態(tài)綁定,通過(guò)定義通用上下文類context并以策略作為模板參數(shù),使不同策略在編譯期實(shí)例化為不同類版本,避免運(yùn)行時(shí)判斷,提升性能和類型安全性。2. 利用模板特化可定制不同類型的策略行為,在通用邏輯基礎(chǔ)上對(duì)特定類型進(jìn)行差異化處理,適合策略差異集中在某些類型而非整體替換的場(chǎng)景。3. 借助if constexpr可在編譯期根據(jù)模板參數(shù)選擇執(zhí)行路徑,適用于策略差異較小、希望統(tǒng)一接口并在同一類中處理的情況,減少多個(gè)類定義,便于維護(hù)。這三種方法可根據(jù)策略復(fù)雜度和復(fù)用需求單獨(dú)或組合使用,實(shí)現(xiàn)高效的編譯期策略選擇。
在一些需要靈活切換算法或行為的 c++ 項(xiàng)目中,策略模式是個(gè)常用的解耦設(shè)計(jì)。而如果能在編譯期就確定具體策略,不僅能避免運(yùn)行時(shí)的條件判斷,還能提升性能和類型安全性。用模板來(lái)實(shí)現(xiàn)策略模式,并結(jié)合模板特化、if constexpr 等特性,可以很好地做到這一點(diǎn)。
下面從幾個(gè)實(shí)際開(kāi)發(fā)中常見(jiàn)的需求點(diǎn)出發(fā),講講怎么用模板做編譯期策略選擇的設(shè)計(jì)。
模板參數(shù)傳入策略類型
最直接的方式是把策略作為模板參數(shù)傳入一個(gè)上下文類(Context)。這樣不同的策略會(huì)在編譯期被實(shí)例化為不同的類版本,彼此獨(dú)立,互不影響。
template <typename Strategy> class Context { public: void execute() { strategy_.doSomething(); } private: Strategy strategy_; };
使用時(shí)只需指定不同的策略類型:
struct StrategyA { void doSomething() { std::cout << "Strategy An"; } }; struct StrategyB { void doSomething() { std::cout << "Strategy Bn"; } }; Context<StrategyA> ctxA; ctxA.execute(); // 輸出 Strategy A Context<StrategyB> ctxB; ctxB.execute(); // 輸出 Strategy B
這種方式的好處是完全靜態(tài)綁定,沒(méi)有虛函數(shù)開(kāi)銷,適合策略數(shù)量固定、不頻繁變化的場(chǎng)景。
使用模板特化定制不同策略行為
如果你希望根據(jù)不同類型執(zhí)行略微不同的邏輯,而不是完全替換整個(gè)策略類,可以用模板特化來(lái)實(shí)現(xiàn)。
比如你有一個(gè)通用的計(jì)算類,但對(duì)某些數(shù)據(jù)類型需要特殊處理:
template <typename T> struct Calculator { void compute(const T& value) { std::cout << "General computation for " << value << "n"; } }; // 特化某個(gè)類型的行為 template <> struct Calculator<int> { void compute(int value) { std::cout << "Special handling for int: " << value * 2 << "n"; } };
調(diào)用方式如下:
Calculator<double> calcD; calcD.compute(3.14); // 輸出 General computation for 3.14 Calculator<int> calcI; calcI.compute(5); // 輸出 Special handling for int: 10
這種做法適合策略差異集中在某些類型上,不需要整體替換策略的情況。
利用 if constexpr 實(shí)現(xiàn)編譯期分支選擇
C++17 引入了 if constexpr,可以在編譯期根據(jù)模板參數(shù)決定走哪條邏輯路徑。這種方式特別適合策略之間差異不大、但又不想拆成多個(gè)類的情況。
舉個(gè)例子:
enum class StrategyType { Fast, Accurate }; template <StrategyType T> class Processor { public: void process(int value) { if constexpr (T == StrategyType::Fast) { std::cout << "Fast mode: " << value + 1 << "n"; } else if constexpr (T == StrategyType::Accurate) { std::cout << "Accurate mode: " << value * 2 << "n"; } } };
使用時(shí)通過(guò)模板參數(shù)控制策略:
Processor<StrategyType::Fast> fastProc; fastProc.process(10); // 輸出 Fast mode: 11 Processor<StrategyType::Accurate> accurateProc; accurateProc.process(10); // 輸出 Accurate mode: 20
這種方法省去了多個(gè)類的定義,適合策略間只是邏輯微調(diào)的情況,也便于維護(hù)統(tǒng)一接口。
小結(jié)一下
- 如果你希望每個(gè)策略完全獨(dú)立,用模板參數(shù)傳入策略類是最清晰的做法。
- 如果只是針對(duì)某些類型有特殊邏輯,模板特化是個(gè)輕量級(jí)的選擇。
- 如果策略之間差異小,想在一個(gè)類里搞定,可以用 if constexpr 來(lái)做編譯期分支判斷。
基本上就這些。這幾種方法都可以單獨(dú)或組合使用,關(guān)鍵看你的策略變體復(fù)雜程度和是否需要復(fù)用部分邏輯。