• C++设计模式——策略模式


    策略模式

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。

    策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,但是,用户需要知道各种算法的具体情况。就像上面的加班工资,不同的加班情况,有不同的算法。我们不能在程序中将计算工资的算法进行硬编码,而是能自由的变化的。这就是策略模式。

     

    UML类图

    Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;
    ConcreteStrategy:实现Strategy接口的具体算法;
    Context:使用一个ConcreteStrategy对象来配置;维护一个对Stategy对象的引用,同时,可以定义一个接口来让Stategy访问它的数据。

     

    使用场合

    当存在以下情况时使用Strategy模式:

    1. 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法;
    2. 需要使用一个算法的不同变体;
    3. 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;
    4. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以替代这些条件语句。(是不是和状态模式有点一样哦?)

     

    代码实现

    首先实现最单纯的策略模式,代码如下:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 // The abstract strategy
     5 class Strategy
     6 {
     7 public:
     8      virtual void AlgorithmInterface() = 0;
     9 };
    10 
    11 class ConcreteStrategyA : public Strategy
    12 {
    13 public:
    14      void AlgorithmInterface()
    15      {
    16           cout<<"I am from ConcreteStrategyA."<<endl;
    17      }
    18 };
    19 
    20 class ConcreteStrategyB : public Strategy
    21 {
    22 public:
    23      void AlgorithmInterface()
    24      {
    25           cout<<"I am from ConcreteStrategyB."<<endl;
    26      }
    27 };
    28 
    29 class ConcreteStrategyC : public Strategy
    30 {
    31 public:
    32      void AlgorithmInterface()
    33      {
    34           cout<<"I am from ConcreteStrategyC."<<endl;
    35      }
    36 };
    37 
    38 class Context
    39 {
    40 public:
    41      Context(Strategy *pStrategyArg) : pStrategy(pStrategyArg)
    42      {
    43      }
    44      void ContextInterface()
    45      {
    46           pStrategy->AlgorithmInterface();
    47      }
    48 private:
    49      Strategy *pStrategy;
    50 };
    51 
    52 int main()
    53 {
    54      // Create the Strategy
    55      Strategy *pStrategyA = new ConcreteStrategyA;
    56      Strategy *pStrategyB = new ConcreteStrategyB;
    57      Strategy *pStrategyC = new ConcreteStrategyC;
    58      Context *pContextA = new Context(pStrategyA);
    59      Context *pContextB = new Context(pStrategyB);
    60      Context *pContextC = new Context(pStrategyC);
    61      pContextA->ContextInterface();
    62      pContextB->ContextInterface();
    63      pContextC->ContextInterface();
    64 
    65      if (pStrategyA) delete pStrategyA;
    66      if (pStrategyB) delete pStrategyB;
    67      if (pStrategyC) delete pStrategyC;
    68 
    69      if (pContextA) delete pContextA;
    70      if (pContextB) delete pContextB;
    71      if (pContextC) delete pContextC;
    72 }

    在实际操作的过程中,我们会发现,在main函数中,也就是在客户端使用策略模式时,会创建非常多的Strategy,而这样就莫名的增加了客户端的压力,让客户端的复杂度陡然增加了。那么,我们就可以借鉴简单工厂模式,使策略模式和简单工厂模式相结合,从而减轻客户端的压力,代码实现如下:

      1 #include <iostream>
      2 using namespace std;
      3 
      4 // Define the strategy type
      5 typedef enum StrategyType
      6 {
      7     StrategyA,
      8     StrategyB,
      9     StrategyC
     10 }STRATEGYTYPE;
     11 
     12 // The abstract strategy
     13 class Strategy
     14 {
     15 public:
     16     virtual void AlgorithmInterface() = 0;
     17     virtual ~Strategy() = 0; // 谢谢hellowei提出的bug,具体可以参见评论
     18 };
     19 
     20 Strategy::~Strategy()
     21 {}
     22 
     23 class ConcreteStrategyA : public Strategy
     24 {
     25 public:
     26     void AlgorithmInterface()
     27     {
     28         cout << "I am from ConcreteStrategyA." << endl;
     29     }
     30 
     31     ~ConcreteStrategyA(){}
     32 };
     33 
     34 class ConcreteStrategyB : public Strategy
     35 {
     36 public:
     37     void AlgorithmInterface()
     38     {
     39         cout << "I am from ConcreteStrategyB." << endl;
     40     }
     41 
     42     ~ConcreteStrategyB(){}
     43 };
     44 
     45 class ConcreteStrategyC : public Strategy
     46 {
     47 public:
     48     void AlgorithmInterface()
     49     {
     50         cout << "I am from ConcreteStrategyC." << endl;
     51     }
     52 
     53     ~ConcreteStrategyC(){}
     54 };
     55 
     56 class Context
     57 {
     58 public:
     59     Context(STRATEGYTYPE strategyType)
     60     {
     61         switch (strategyType)
     62         {
     63         case StrategyA:
     64             pStrategy = new ConcreteStrategyA;
     65             break;
     66 
     67         case StrategyB:
     68             pStrategy = new ConcreteStrategyB;
     69             break;
     70 
     71         case StrategyC:
     72             pStrategy = new ConcreteStrategyC;
     73             break;
     74 
     75         default:
     76             break;
     77         }
     78     }
     79 
     80     ~Context()
     81     {
     82         if (pStrategy) delete pStrategy;
     83     }
     84 
     85     void ContextInterface()
     86     {
     87         if (pStrategy)
     88             pStrategy->AlgorithmInterface();
     89     }
     90 
     91 private:
     92     Strategy *pStrategy;
     93 };
     94 
     95 int main()
     96 {
     97     Context *pContext = new Context(StrategyA);
     98     pContext->ContextInterface();
     99 
    100     if (pContext) delete pContext;
    101 }

    在上面这个代码中,其实,我们可能看到的更多的是简单工厂模式的应用,我们将策略模式将简单工厂模式结合在了一起,让客户端使用起来更轻松。

     

    总结

    策略模式和状态模式,是大同小异的;状态模式讲究的是状态的变化,和不同状态下,执行的不同行为;而策略模式侧重于同一个动作,实现该行为的算法的不同,不同的策略封装了不同的算法。策略模式适用于实现某一功能,而实现该功能的算法是经常改变的情况。在实际工作中,遇到了实际的场景,可能会有更深的体会。比如,我们做某一个系统,该系统可以适用于各种数据库,我们都知道,连接某一种数据库的方式是不一样的,也可以说,连接数据库的“算法”都是不一样的。这样,我们就可以使用策略模式来实现不同的连接数据库的策略,从而实现数据库的动态变换。

  • 相关阅读:
    操作系统原理5——文件管理
    Hadoop worldcount
    Java Future源码分析
    HBase入门教程
    Java自定义cas操作
    dubbo客户端源码分析(一)
    log4j2配置文件
    paxos协议
    Guava限流工具RateLimiter使用
    jvm内置锁synchronized不能被中断
  • 原文地址:https://www.cnblogs.com/ring1992/p/9593575.html
Copyright © 2020-2023  润新知