【C++設計模式之Strategy策略模式】

C++設計模式之Strategy策略模式

  • 模式定義
  • 核心思想
  • 動機(Motivation)
  • 結構(Structure)
  • 實現步驟
    • 1. 定義策略接口(基于繼承)
    • 2.實現具體策略
    • 3.上下文類(Context)
    • 4. 在main中調用
  • 應用場景(基于繼承)
    • 1.定義策略接口
    • 2.實現具體策略
    • 3.上下文類(Context)
    • 4.在main中調用測試
  • 現代 C++ 優化(基于 std::function)
    • 1.使用函數對象替代接口
    • 2.定義策略函數
    • 3.main.cpp中使用示例
  • 優化方向
    • 1.編譯時策略(模板實現)
    • 2.線程安全策略切換
  • 要點總結


模式定義

策略模式:定義一系列算法,把她們一個個封裝起來,并且使它們可以相互替換(變化)。該模式使得算法可以獨立于使用它的客戶程序(穩定)而變化(擴展,子類化)。
需要區分策略模式和之前提到的模板方法模式的不同,模板方法是通過繼承來改變部分步驟,而策略模式是通過組合不同的策略對象來改變整體行為。

核心思想

  • 解耦算法與客戶端:將算法邏輯從主類中分離,避免代碼臃腫。
  • 運行時動態切換:通過更換策略對象,靈活改變程序行為。
  • 開閉原則:新增算法無需修改現有代碼,只需添加新策略類。

動機(Motivation)

  • 在軟件構建過程中,某些對象使用的算法可能多種多樣,經常改變,如果將這些算法都編碼到對象中,將會使對象變得異常復雜;而且有時候支持不使用的算法也是一個性能負擔。
  • 如何在運行時根據需要透明地更改對象的算法?將算法與對象本身解耦,從而避免上述問題?

結構(Structure)

在這里插入圖片描述

實現步驟

1. 定義策略接口(基于繼承)

startegy.h

#pragma once
class Strategy {//策略模式的運算法則
public:virtual ~Strategy() {}virtual void doSomething() = 0;
};

2.實現具體策略

concretestrategy.h

#pragma once
#include<iostream>
#include"strategy.h"
class ConcreteStrategy1 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy1 doSomething" << std::endl;}
};class ConcreteStrategy2 :public Strategy {
public:void doSomething()override {std::cout << "ConcreteStrategy2 doSomething" << std::endl;}
};

3.上下文類(Context)

持有策略對象的引用,并委托算法執行

context.h

#pragma once
#include"strategy.h"
class Context {
public://構造函數設置具體策略Context(Strategy *strategy) {strategy_ = strategy;}//封裝后的策略方法void doAnything() {strategy_->doSomething();}private:Strategy *strategy_ = nullptr;
};

4. 在main中調用

#include "concretestrategy.h"
#include "context.h"int main()
{Strategy *strategy = new ConcreteStrategy1();//聲明上下文對象Context context(strategy);context.doAnything();delete strategy;
}

應用場景(基于繼承)

傳統實現(基于繼承),實現快速排序算法,歸并排序算法的策略模式

1.定義策略接口

sortingstrategy.h

#pragma once
#include<iostream>
#include<vector>//策略接口:定義算法的抽象操作
class SortingStrategy {
public:virtual ~SortingStrategy() = default;virtual void sort(std::vector<int>&data)const = 0;
};

2.實現具體策略

#pragma once
#include"sortingstrategy.h"
//具體策略1:快速排序
class QuickSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with QuickSort\n";//快速排序具體實現}
};class MergeSort :public SortingStrategy
{
public:void sort(std::vector<int>&data)const override {std::cout << "Sorting with MergeSort\n";//歸并排序具體實現}
};

3.上下文類(Context)

持有策略對象的引用,并委托算法執行

context.h

#pragma once
#include"concretesorting.h"
class Sorter {
private:std::unique_ptr<SortingStrategy> strategy_;  //使用智能指針管理策略對象public:explicit Sorter(std::unique_ptr<SortingStrategy> strategy):strategy_(std::move(strategy)){}//動態切換策略void setStrategy(std::unique_ptr<SortingStrategy>strategy) {strategy_ = std::move(strategy);}//執行排序void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_->sort(data);}}
};

4.在main中調用測試

#include"context.h"
#include<vector>int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(std::make_unique<QuickSort>());sorter.executeSort(data);    //輸出:Sorting with QuickSortsorter.setStrategy(std::make_unique<MergeSort>());sorter.executeSort(data);    //輸出Sorting with MergeSortreturn 0;
}

現代 C++ 優化(基于 std::function)

1.使用函數對象替代接口

無需繼承策略接口,直接通過std::function封裝算法:
context.h

#pragma once
#include<functional>
#include<vector>class Sorter {
public:using Strategy = std::function<void(std::vector<int>&)>;explicit Sorter(Strategy strategy):strategy_(std::move(strategy)){}void setStrategy(Strategy strategy) {strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {if (strategy_) {strategy_(data);}}private:Strategy strategy_;
};

2.定義策略函數

context.h

void quickSort(std::vector<int>& data) {std::cout << "Sorting with QuickSort\n";// 快速排序實現...
}void mergeSort(std::vector<int>& data) {std::cout << "Sorting with MergeSort\n";// 歸并排序實現...
}// 支持 Lambda 表達式
auto bubbleSort = [](std::vector<int>& data) {std::cout << "Sorting with BubbleSort\n";// 冒泡排序實現...
};

3.main.cpp中使用示例

#include"context.h"int main()
{std::vector<int> data = { 5,2,7,1,9 };Sorter sorter(quickSort);sorter.executeSort(data);      //輸出Sorting with QuickSortsorter.setStrategy(mergeSort); //輸出Sorting with MergeSortsorter.executeSort(data);sorter.setStrategy(bubbleSort);//輸出Sorting with BubbleSortsorter.executeSort(data);//直接傳達Lambdasorter.setStrategy([](std::vector<int>&data) {std::cout << "Custom Lambda Strategy \n";});sorter.executeSort(data);return 0;
}

優化方向

1.編譯時策略(模板實現)

通過模板參數在編譯時綁定 策略,消除運行時開銷:

#pragma once
#include<vector>
#include<iostream>template<typename Strategy>
class ComplieTimeSorter {
public:void executeSort(std::vector<int>&data)const {Strategy::sort(data);   //策略需要提供靜態方法}
};//策略類無需繼承接口
struct QuickSort {static void sort(std::vector<int>&data) {std::cout << "Compile-Time QuickSort \n";}
};int main()
{std::vector<int> data = { 5,2,7,1,9 };ComplieTimeSorter<QuickSort>sorter;sorter.executeSort(data);  //輸出Complie-Time QuickSortsystem("pause");return 0;
}

2.線程安全策略切換

在多線程環境中安全且策略:

#pragma once
#include<mutex>
#include<vector>class ThreadSafeSorter {
public:using Strategy = std::function<void(std::vector<int>&)>;void setStrategy(Strategy strategy) {std::lock_guard<std::mutex>lock(mtx_);strategy_ = std::move(strategy);}void executeSort(std::vector<int>&data)const {std::lock_guard<std::mutex>lock(mtx_);if (strategy_) {strategy_(data);}}
private:mutable std::mutex mtx_;Strategy strategy_;
};

要點總結

  • Strategy及其子類為組件提供了一系列可重用的算法,從而可以使得類型在運行時方便地根據需要在各個算法之間進行切換。
  • Strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句,就是在解耦合。含有許多條件判斷語句的代碼通常都需要Strategy模式。
  • 如果Strategy對象沒有實例變量,那么各個上下文可以共享同一個Strategy對象,從而節省對象開銷。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80170.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80170.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80170.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python企業級MySQL數據庫開發實戰指南

簡介 Python與MySQL的完美結合是現代Web應用和數據分析系統的基石,能夠創建高效穩定的企業級數據庫解決方案。本文將從零開始,全面介紹如何使用Python連接MySQL數據庫,設計健壯的表結構,實現CRUD操作,并掌握連接池管理、事務處理、批量操作和防止SQL注入等企業級開發核心…

matlab轉python

1 matlab2python開源程序 https://blog.csdn.net/qq_43426078/article/details/123384265 2 網址 轉換網址&#xff1a;https://app.codeconvert.ai/code-converter?inputLangMatlab&outputLangPython 文件比較網址&#xff1a;https://www.diffchecker.com/text-comp…

Vue 3 中編譯時和運行時的概念區別

文章目錄 前言Vue 3 中的編譯時 vs 運行時區別模板在編譯時轉化為渲染函數編譯時的優化處理運行時的工作:創建組件實例與渲染流程前言 詳細整理 Vue 3 中編譯時和運行時的概念區別,并重點解釋為什么組件實例是在運行時創建的。 我會結合官方文檔、源碼分析和社區解釋,確保內…

Spring 框架實戰:如何實現高效的依賴注入,優化項目結構?

Spring 框架實戰&#xff1a;如何實現高效的依賴注入&#xff0c;優化項目結構&#xff1f; 在當今的 Java 開發領域&#xff0c;Spring 框架占據著舉足輕重的地位。而依賴注入作為 Spring 的核心概念之一&#xff0c;對于構建高效、靈活且易于維護的項目結構有著關鍵作用。本…

創建虛擬服務時實現持久連接。

在調度器中配置虛擬服務&#xff0c;實現持久性連接&#xff0c;解決會話保持問題。 -p 【timeout】 -p 300 這5分鐘之內調度器會把來自同一個客戶端的請求轉發到同一個后端服務器。【不管使用的調度算法是什么。】【稱為持久性連接。】 作用&#xff1a;將客戶端一段時間…

說下RabbitMQ的整體架構

RabbitMQ 是一個基于 AMQP&#xff08;Advanced Message Queuing Protocol&#xff09; 協議的開源消息中間件&#xff0c;RabbitMQ的整體架構圍繞消息的生產、路由、存儲和消費設計&#xff0c;旨在實現高效、可靠的消息傳遞&#xff0c;它由多個核心組件協同工作。 核心組件 …

STM32--GPIO

教程 視頻 博主教程 STM32系統結構圖 GPIO GPIO&#xff08;General Purpose Input/Output&#xff09;是STM32內部的一種外設。 一個STM32芯片內存在多個GPIO外設&#xff0c;每個GPIO外設有16個引腳&#xff1b; 比如GPIOA&#xff1a;PA0~PA15; GPIOB&#xff1a;PB0~…

QUIC協議優化:HTTP_3環境下的超高速異步抓取方案

摘要 隨著 QUIC 和 HTTP/3 的普及&#xff0c;基于 UDP 的連接復用與內置加密帶來了遠超 HTTP/2 的性能提升&#xff0c;可顯著降低連接握手與擁塞恢復的開銷。本文以爬取知乎熱榜數據為目標&#xff0c;提出一種基于 HTTPX aioquic 的異步抓取方案&#xff0c;并結合代理 IP設…

[論文閱讀]MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System

MCP Guardian: A Security-First Layer for Safeguarding MCP-Based AI System http://arxiv.org/abs/2504.12757 推出了 MCP Guardian&#xff0c;這是一個框架&#xff0c;通過身份驗證、速率限制、日志記錄、跟蹤和 Web 應用程序防火墻 &#xff08;WAF&#xff09; 掃描來…

Redis客戶端緩存的4種實現方式

Redis作為當今最流行的內存數據庫和緩存系統&#xff0c;被廣泛應用于各類應用場景。然而&#xff0c;即使Redis本身性能卓越&#xff0c;在高并發場景下&#xff0c;應用與Redis服務器之間的網絡通信仍可能成為性能瓶頸。 這時&#xff0c;客戶端緩存技術便顯得尤為重要。 客…

eNSP中路由器OSPF協議配置完整實驗和命令解釋

本實驗使用三臺華為路由器&#xff08;R1、R2和R3&#xff09;相連&#xff0c;配置OSPF協議實現網絡互通。拓撲結構如下&#xff1a; 實驗IP規劃 R1: GE0/0/0: 192.168.12.1/24 (Area 0)Loopback0: 1.1.1.1/32 (Area 0) R2: GE0/0/0: 192.168.12.2/24 (Area 0)GE0/0/1: 192.…

內網滲透——紅日靶場三

目錄 一、前期準備 二、外網探測 1.使用nmap進行掃描 2.網站信息收集 3.漏洞復現(CVE-2021-23132) 4.disable_function繞過 5.反彈shell&#xff08;也&#xff0c;并不是&#xff09; 6.SSH登錄 7.權限提升&#xff08;臟牛漏洞&#xff09; 8.信息收集 9.上線msf 三…

解決Win11下MySQL服務無法開機自啟動問題

問題描述 在win11系統中&#xff0c;明明將MySQL服務設置成了自動啟動&#xff0c;但在重啟電腦后MySQL服務還是無法自動啟動&#xff0c;每次都要重新到計算機管理的服務中找到服務再手動啟動。 解決方式 首先確保mysql服務的啟動類型為自動。 設置方法&#xff1a;找到此電…

后端項目進度匯報

項目概述 本項目致力于構建一個先進的智能任務自動化平臺。其核心技術是一套由大型語言模型&#xff08;LLM&#xff09;驅動的后端系統。該系統能夠模擬一個多角色協作的團隊&#xff0c;通過一系列精心設計或動態生成的處理階段&#xff0c;來高效完成各種復雜任務&#xff…

深度學習中學習率調整:提升食物圖像分類模型性能的關鍵實踐

深度學習中學習率調整&#xff1a;提升食物圖像分類模型性能的關鍵實踐 接上篇保存最優模型&#xff0c;在深度學習模型訓練過程中&#xff0c;學習率作為核心超參數&#xff0c;其設置直接影響模型的收斂速度與最終性能。本文將結合食物圖像分類項目&#xff0c;深入探討學習…

Vue 3零基礎入門:從環境搭建到第一個組件

Vue 3零基礎入門&#xff1a;從環境搭建到第一個組件 一、Vue 3簡介 Vue.js是一款漸進式JavaScript框架&#xff0c;用于構建用戶界面。Vue 3是Vue的最新主要版本&#xff0c;于2020年9月發布&#xff0c;帶來了許多改進和新特性&#xff1a; 更快的渲染速度更小的包體積Com…

為了結合后端而學習前端的學習日志(1)——純CSS靜態卡片案例

前端設計專欄 使用純CSS創建簡潔名片卡片的學習實踐 在這篇技術博客中&#xff0c;我將分享我的前端學習過程&#xff0c;如何使用純HTML和CSS創建一個簡潔美觀的名片式卡片&#xff0c;就像我博客首頁展示的那樣。這種卡片設計非常適合作為個人簡介、產品展示或團隊成員介紹…

k8s監控方案實踐(一):部署Prometheus與Node Exporter

k8s監控方案實踐&#xff08;一&#xff09;&#xff1a;部署Prometheus與Node Exporter 文章目錄 k8s監控方案實踐&#xff08;一&#xff09;&#xff1a;部署Prometheus與Node Exporter一、Prometheus簡介二、PrometheusNode Exporter實戰部署1. 創建Namespace&#xff08;p…

谷歌最新推出的Gemini 2.5 Flash人工智能模型因其安全性能相較前代產品出現下滑

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

【Python】PDF文件處理(PyPDF2、borb、fitz)

Python提供了多種方法和庫用于處理PDF文件&#xff0c;這些工具可以幫助開發者實現諸如讀取、寫入、合并、拆分以及壓縮等功能。以下是幾個常用的Python PDF操作庫及其基本用法&#xff08;PyPDF2、borb、fitz&#xff09;。 1. PyPDF2 PyPDF2 是一個功能強大的庫&#xff0…