C++ 筹划模式——战略模式

[复制链接]
发表于 2026-2-4 14:10:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
战略模式

战略模式是一种举动筹划模式,它界说了一系列算法,将每一个算法封装起来,并使它们可以互换。战略模式让算法的变革独立于使用算法的客户。
引入"战略“筹划模式的界说:界说一些列算法类(战略类),将每个算法封装起来,让他们可以相互更换。换句话说,战略模式通常把一系列算法封装到一系列具体战略类中作为抽象战略类的字类,然后根据现实须要实用这些字类。
告急构成部分



  • 战略接口 (Strategy):界说一个同一的接口,声明全部支持的算法(战略)的方法。客户端通过这个接口调用具体战略。
  • 具体战略类 (Concrete Strategy):实现战略接口,界说具体的算法或举动。每个具体战略类实现差别的算法。
  • 上下文类 (Context):持有对战略接口的引用,负责调用具体战略的方法。上下文类可以在运行时动态地切换战略。
例一:渐渐重构并引入战略模式

假设我们须要实现差别的排序算法(如冒泡排序和快速排序)。最初的实现大概是重复的代码。渐渐重构的过程如下:
第一步:初始实现

为每种排序算法编写独立的处置惩罚逻辑:
  1. #include <iostream>
  2. #include <vector>
  3. void bubbleSort(std::vector<int>& arr) {
  4.     for (size_t i = 0; i < arr.size() - 1; ++i) {
  5.         for (size_t j = 0; j < arr.size() - i - 1; ++j) {
  6.             if (arr[j] > arr[j + 1]) {
  7.                 std::swap(arr[j], arr[j + 1]);
  8.             }
  9.         }
  10.     }
  11. }
  12. void quickSort(std::vector<int>& arr, int low, int high) {
  13.     if (low < high) {
  14.         int pivot = arr[high];
  15.         int i = low - 1;
  16.         for (int j = low; j < high; ++j) {
  17.             if (arr[j] < pivot) {
  18.                 ++i;
  19.                 std::swap(arr[i], arr[j]);
  20.             }
  21.         }
  22.         std::swap(arr[i + 1], arr[high]);
  23.         quickSort(arr, low, i);
  24.         quickSort(arr, i + 2, high);
  25.     }
  26. }
  27. int main() {
  28.     std::vector<int> data = {5, 3, 8, 6, 2};
  29.     bubbleSort(data);
  30.     // 或者使用 quickSort(data, 0, data.size() - 1);
  31.     return 0;
  32. }
复制代码
第二步:提取共性并实现战略接口

辨认出排序的共性步调,并创建一个战略接口 SortStrategy,界说排序方法:
  1. class SortStrategy {
  2. public:
  3.     virtual void sort(std::vector<int>& arr) = 0; // 策略接口
  4. };
复制代码
第三步:实现具体战略类

为每种排序算法实现具体战略类,重写排序方法:
  1. class BubbleSort : public SortStrategy {
  2. public:
  3.     void sort(std::vector<int>& arr) override {
  4.         for (size_t i = 0; i < arr.size() - 1; ++i) {
  5.             for (size_t j = 0; j < arr.size() - i - 1; ++j) {
  6.                 if (arr[j] > arr[j + 1]) {
  7.                     std::swap(arr[j], arr[j + 1]);
  8.                 }
  9.             }
  10.         }
  11.     }
  12. };
  13. class QuickSort : public SortStrategy {
  14. public:
  15.     void sort(std::vector<int>& arr) override {
  16.         quickSort(arr, 0, arr.size() - 1);
  17.     }
  18. private:
  19.     void quickSort(std::vector<int>& arr, int low, int high) {
  20.         if (low < high) {
  21.             int pivot = arr[high];
  22.             int i = low - 1;
  23.             for (int j = low; j < high; ++j) {
  24.                 if (arr[j] < pivot) {
  25.                     ++i;
  26.                     std::swap(arr[i], arr[j]);
  27.                 }
  28.             }
  29.             std::swap(arr[i + 1], arr[high]);
  30.             quickSort(arr, low, i);
  31.             quickSort(arr, i + 2, high);
  32.         }
  33.     }
  34. };
复制代码
第四步:实现上下文类

创建一个上下文类 Sorter,用于使用战略:
  1. class Sorter {
  2. private:
  3.     SortStrategy* strategy;
  4. public:
  5.     Sorter(SortStrategy* strategy) : strategy(strategy) {}
  6.     void setStrategy(SortStrategy* strategy) {
  7.         this->strategy = strategy;
  8.     }
  9.     void sort(std::vector<int>& arr) {
  10.         strategy->sort(arr);
  11.     }
  12. };
复制代码
战略模式 UML 图


战略模式的 UML 图剖析



  • 上下文类 (Context):

    • Sorter 类:它是上下文类,负责使用战略并持有战略的引用。Sorter 类通过 setStrategy 方法设置具体的排序战略,并通过 sort 方法调用该战略举行排序。

  • 抽象战略类 (Strategy):

    • SortStrategy 类:这是战略接口,界说了一个公共方法 sort,该方法由具体战略类实现。它确保全部具体战略类都有同等的接口。

  • 具体战略类 (Concrete Strategy):

    • BubbleSort 类:实现了 SortStrategy 接口,提供了冒泡排序的具体实现。
    • QuickSort 类:实现了 SortStrategy 接口,提供了快速排序的具体实现。

例二:渐渐重构并引入战略模式

第一步:初始实现

起首,从一个简朴的实现开始,此中战斗者类直接实现道具使用逻辑。
  1. #include <iostream>
  2. using namespace std;
  3. class Fighter {
  4. public:
  5.     Fighter(int life) : m_life(life) {}
  6.    
  7.     void UseBXD() { // 使用补血丹
  8.         m_life += 200;
  9.         cout << "使用补血丹,生命值增加200。" << endl;
  10.     }
  11.     void UseDHD() { // 使用大还丹
  12.         m_life += 300;
  13.         cout << "使用大还丹,生命值增加300。" << endl;
  14.     }
  15.     void UseSHD() { // 使用守护丹
  16.         m_life += 500;
  17.         cout << "使用守护丹,生命值增加500。" << endl;
  18.     }
  19.     int GetLife() {
  20.         return m_life;
  21.     }
  22. private:
  23.     int m_life;
  24. };
  25. int main() {
  26.     Fighter warrior(1000);
  27.     cout << "初始生命值:" << warrior.GetLife() << endl;
  28.     warrior.UseDHD();
  29.     cout << "当前生命值:" << warrior.GetLife() << endl;
  30.     warrior.UseBXD();
  31.     cout << "当前生命值:" << warrior.GetLife() << endl;
  32.     warrior.UseSHD();
  33.     cout << "当前生命值:" << warrior.GetLife() << endl;
  34.     return 0;
  35. }
复制代码
第二步:提取共性并实现战略接口

在该实现中,Fighter 类包罗全部道具使用的逻辑。可以提取出道具使用的共性,界说一个道具战略接口。
  1. class ItemStrategy {
  2. public:
  3.     virtual void UseItem(Fighter* fighter) = 0;
  4.     virtual ~ItemStrategy() {}
  5. };
复制代码
第三步:实现具体战略类

为每种道具创建具体的战略类,实现 ItemStrategy 接口。


  • 补血丹战略类:
  1. class ItemStrategy_BXD : public ItemStrategy {
  2. public:
  3.     void UseItem(Fighter* mainobj) override {
  4.         mainobj->SetLife(mainobj->GetLife() + 200); // 补充200点生命值
  5.     }
  6. };
复制代码


  • 大还丹战略类:
  1. class ItemStrategy_DHD : public ItemStrategy {
  2. public:
  3.     void UseItem(Fighter* mainobj) override {
  4.         mainobj->SetLife(mainobj->GetLife() + 300); // 补充300点生命值
  5.     }
  6. };
复制代码


  • 守卫丹战略类:
  1. class ItemStrategy_SHD : public ItemStrategy {
  2. public:
  3.     void UseItem(Fighter* mainobj) override {
  4.         mainobj->SetLife(mainobj->GetLife() + 500); // 补充500点生命值
  5.     }
  6. };
复制代码
第四步:实现上下文类:

在 Fighter 类中添加设置道具战略的方法,并移除具体的道具使用逻辑,并界说战斗者的子类(可以不须要字类)。
  1. class Fighter {
  2. public:
  3.     Fighter(int life) : m_life(life), itemStrategy(nullptr) {}
  4.     void SetItemStrategy(ItemStrategy* strategy) {
  5.         itemStrategy = strategy;
  6.     }
  7.     void UseItem() {
  8.         if (itemStrategy) {
  9.             itemStrategy->UseItem(this);
  10.         }
  11.     }
  12.     int GetLife() {
  13.         return m_life;
  14.     }
  15.     void SetLife(int life) {
  16.         m_life = life;
  17.     }
  18. private:
  19.     int m_life;
  20.     ItemStrategy* itemStrategy;
  21. };
  22. class F_Warrior : public Fighter {
  23. public:
  24.     F_Warrior(int life, int magic, int attack)
  25.         : Fighter(life, magic, attack) {}
  26.     // 其他战士特有的方法
  27. };
  28. class F_Mage : public Fighter {
  29. public:
  30.     F_Mage(int life, int magic, int attack)
  31.         : Fighter(life, magic, attack) {}
  32.     // 其他法师特有的方法
  33. };
复制代码
第五步:更新主函数

更新主函数以使用新的战略模式布局。
  1. int main() {
  2.     Fighter warrior(1000);
  3.     cout << "初始生命值:" << warrior.GetLife() << endl;
  4.     ItemStrategy* strategy1 = new ItemStrategy_DHD();
  5.     warrior.SetItemStrategy(strategy1);
  6.     warrior.UseItem();
  7.     cout << "当前生命值:" << warrior.GetLife() << endl;
  8.     ItemStrategy* strategy2 = new ItemStrategy_BXD();
  9.     warrior.SetItemStrategy(strategy2);
  10.     warrior.UseItem();
  11.     cout << "当前生命值:" << warrior.GetLife() << endl;
  12.     ItemStrategy* strategy3 = new ItemStrategy_SHD();
  13.     warrior.SetItemStrategy(strategy3);
  14.     warrior.UseItem();
  15.     cout << "当前生命值:" << warrior.GetLife() << endl;
  16.     delete strategy1;
  17.     delete strategy2;
  18.     delete strategy3;
  19.     return 0;
  20. }
复制代码
战略模式 UML 图


战略模式的 UML 图剖析



  • Context(情况类):也叫上下文类,是使用算法的脚色,该类中维持着一个对抽象战略类的指针或引用。这里指Fighter类。
  • Stategy(抽象战略类):界说所支持的算法的公共接口,是全部战略类的父类。这里指 ItemStrategy 类。
  • ConcreteStrategy(具体战略类):抽象战略类的子类,实现抽象战略类中声明的接口。这里指ItemStrategy_BXD、ItemStrategy_DHD、ItemStrategy_SHD类。
战略模式优缺点

优点:


  • 机动性:可以在运行时选择差别的战略,增长了步伐的机动性和可扩展性。
  • 开放-关闭原则:新的战略可以通过实现战略接口而无需修改现有代码,符合开放-关闭原则。
  • 清楚的职责分离:将差别的算法封装在差别的类中,使得代码更加清楚,易于维护。
  • 淘汰条件语句:制止了使用大量的条件语句(如 if-else 或 switch),使代码布局更加简便。
  • 易于测试:每个战略类可以独立测试,便于单元测试和调试。
缺点:


  • 类的数目增长:每种战略都须要一个新的类,大概导致类的数目增长,增长了体系的复杂性。
  • 客户端必须相识全部战略:客户端须要相识全部可用的战略,以便选择符合的战略,这大概增长了使用的复杂性。
  • 性能开销:在某些情况下,频仍地创建和烧毁战略对象大概导致性能开销。
  • 不得当简朴的算法:对于简朴的算法,使用战略模式大概显得过于复杂,增长了不须要的抽象。
战略模式实用场景



  • 多种算法:当有多个算法可以选择时,战略模式可以将它们封装起来,方便切换。
  • 制止条件语句:当使用大量条件语句来选择算法时,可以使用战略模式来简化代码布局。
  • 动态选择算法:当须要在运行时选择算法时,战略模式提供了机动性。
  • 算法复用:当多个类须要使用同一算法时,可以将算法封装成战略类,促进代码复用。
例一的完备代码

以下是完备的实当代码:
  1. #include <iostream>#include <vector>// 战略接口class SortStrategy{public:    virtual void sort(std::vector<int>& arr) = 0; // 战略接口};// 具体战略:冒泡排序class BubbleSort : public SortStrategy {public:    void sort(std::vector<int>& arr) override {        for (size_t i = 0; i < arr.size() - 1; ++i) {            for (size_t j = 0; j < arr.size() - i - 1; ++j) {                if (arr[j] > arr[j + 1]) {                    std::swap(arr[j], arr[j + 1]);                }            }        }    }};// 具体战略:快速排序class QuickSort : public SortStrategy {public:    void sort(std::vector<int>& arr) override {        quickSort(arr, 0, arr.size() - 1);    }private:    void quickSort(std::vector<int>& arr, int low, int high) {        if (low < high) {            int pivot = arr[high];            int i = low - 1;            for (int j = low; j < high; ++j) {                if (arr[j] < pivot) {                    ++i;                    std::swap(arr[i], arr[j]);                }            }            std::swap(arr[i + 1], arr[high]);            quickSort(arr, low, i);            quickSort(arr, i + 2, high);        }    }};// 上下文类class Sorter {
  2. private:
  3.     SortStrategy* strategy;
  4. public:
  5.     Sorter(SortStrategy* strategy) : strategy(strategy) {}
  6.     void setStrategy(SortStrategy* strategy) {
  7.         this->strategy = strategy;
  8.     }
  9.     void sort(std::vector<int>& arr) {
  10.         strategy->sort(arr);
  11.     }
  12. };
  13. // 示例用法int main() {    std::vector<int> data = {5, 3, 8, 6, 2};    Sorter sorter(new BubbleSort());    sorter.sort(data); // 使用冒泡排序    sorter.setStrategy(new QuickSort());    sorter.sort(data); // 使用快速排序    return 0;}
复制代码
例二的完备代码

  1. #include <iostream>
  2. using namespace std;
  3. class Fighter; // 类前向声明
  4. //道具策略类的父类
  5. class ItemStrategy
  6. {
  7. public:
  8.     virtual void UseItem(Fighter* mainobj) = 0;
  9.     virtual ~ItemStrategy() {}
  10. };
  11. //战斗者父类
  12. class Fighter
  13. {
  14. public:
  15.     Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}
  16.     virtual ~Fighter() {}
  17. public:
  18.     void SetItemStrategy(ItemStrategy* strategy) //设置道具使用的策略
  19.     {
  20.         itemstrategy = strategy;
  21.     }
  22.     void UseItem() //使用道具(吃药)
  23.     {
  24.         itemstrategy->UseItem(this);
  25.     }
  26.     int  GetLife() //获取人物生命值
  27.     {
  28.         return m_life;
  29.     }
  30.     void SetLife(int life) //设置人物生命值
  31.     {
  32.         m_life = life;
  33.     }
  34. private:
  35.     ItemStrategy* itemstrategy = nullptr; //C++11中支持这样初始化
  36. protected:
  37.     int m_life;
  38.     int m_magic;
  39.     int m_attack;
  40. };
  41. //“战士”类,父类为Fighter
  42. class F_Warrior :public Fighter
  43. {
  44. public:
  45.     F_Warrior(int life, int magic, int attack) :Fighter(life, magic, attack) {}
  46. };
  47. //“法师”类,父类为Fighter
  48. class F_Mage :public Fighter
  49. {
  50. public:
  51.     F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {}
  52. };
  53. //补血丹策略类
  54. class ItemStrategy_BXD : public ItemStrategy
  55. {
  56. public:
  57.     virtual void UseItem(Fighter* mainobj)
  58.     {
  59.         mainobj->SetLife(mainobj->GetLife() + 200); //补充200点生命值
  60.         cout << "使用补血丹,生命值增加200。" << endl;
  61.     }
  62. };
  63. //大还丹策略类
  64. class ItemStrategy_DHD : public ItemStrategy
  65. {
  66. public:
  67.     virtual void UseItem(Fighter* mainobj)
  68.     {
  69.         mainobj->SetLife(mainobj->GetLife() + 300); //补充300点生命值
  70.         cout << "使用大还丹,生命值增加300。" << endl;
  71.     }
  72. };
  73. //守护丹策略类
  74. class ItemStrategy_SHD : public ItemStrategy
  75. {
  76. public:
  77.     virtual void UseItem(Fighter* mainobj)
  78.     {
  79.         mainobj->SetLife(mainobj->GetLife() + 500); //补充500点生命值
  80.         cout << "使用守护丹,生命值增加500。" << endl;
  81.     }
  82. };
  83. int main()
  84. {
  85.     // 创建战斗者对象
  86.     Fighter* prole_war = new Fighter(1000, 0, 200);
  87.     // 打印初始生命值
  88.     cout << "初始生命值:" << prole_war->GetLife() << endl;
  89.     // 使用大还丹
  90.     ItemStrategy* strategy1 = new ItemStrategy_DHD();
  91.     prole_war->SetItemStrategy(strategy1);
  92.     prole_war->UseItem();
  93.     cout << "当前生命值:" << prole_war->GetLife() << endl;
  94.     // 使用补血丹
  95.     ItemStrategy* strategy2 = new ItemStrategy_BXD();
  96.     prole_war->SetItemStrategy(strategy2);
  97.     prole_war->UseItem();
  98.     cout << "当前生命值:" << prole_war->GetLife() << endl;
  99.     // 使用守护丹
  100.     ItemStrategy* strategy3 = new ItemStrategy_SHD();
  101.     prole_war->SetItemStrategy(strategy3);
  102.     prole_war->UseItem();
  103.     cout << "当前生命值:" << prole_war->GetLife() << endl;
  104.     // 释放资源
  105.     delete strategy1;
  106.     delete strategy2;
  107.     delete strategy3;
  108.     delete prole_war;
  109.    
  110.     F_Mage mage(800, 300, 100);
  111.     cout << "法师初始生命值:" << mage.GetLife() << endl;
  112.     // 可以为法师设置道具策略并使用
  113.     // ...
  114.     return 0;
  115. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表