策略模式

1 策略模式

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

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

2 UML类图

Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;

ConcreteStrategy:实现Strategy接口的具体算法;

Context:使用一个ConcreteStrategy对象来配置;维护一个对Stategy对象的引用,同时,可以定义一个接口来让Stategy访问它的数据。

3 使用场合

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

许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法;

需要使用一个算法的不同变体;

算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;

一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以替代这些条件语句。(是不是和状态模式有点一样哦?)

4 代码实现

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

复制代码
 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 }

output:

I am from ConcreteStrategyA.
I am from ConcreteStrategyB.
I am from ConcreteStrategyC. 

在实际操作的过程中,我们会发现,在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 }

output:

I am from ConcreteStrategyA.    

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

5 总结

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

本页共20段,1312个字符,3284 Byte(字节)