一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

设计模式之策略模式

  策略模式定义算法家族,分别封装。它们之间可以相互替换,让算法变化,不会影响到用户。优点:适合类中的成员方法为主,算法经常变动;简单了单元测试(因为每个算法都有自己的类,可以通过自己的接口单独测试)。缺点:客户端需要做出判断。

其UML图如下:

  策略模式和简单工厂模式非常相似。具体来讲有个细微的区别就是,简单工厂模式需要根据传递过来的条件判断创建什么样的对象。而策略模式是直接传递给Context一个对象,至于传递什么类型的对象则是需要用户自己去判断。从这一点来讲策略模式遵从了开放-封闭原则,当需要添加不同的算法的时候只需要添加一个算法类就可以了,并不用去修改Context类。而简单工厂模式则破坏了开放-封闭原则,当需要添加不同的对象时候,不仅需要添加响应的类,还需要修改工厂类。这一点无所谓好与坏,主要还是看需求。这两种模式也经常结合起来使用,因为策略模式需要根据需求判断生成算法类对象,而这一部分可以封装成一个简单工厂模式。另一方面,简单工厂模式主要解决的是对象创建问题,而策略模式主要解决的是经常变动算法的问题。

策略模式与简单工厂模式相结合给出的四则运算的示例代码如下:

  1 // StrategyModel.h文件
  2 #pragma once
  3 // 操作基类
  4 template<typename T>
  5 class Operation
  6 {
  7 public:
  8     Operation(T lpa, T rpa);
  9     virtual T getResult() = 0;
 10 protected:
 11     T lpa, rpa;
 12 };
 13 
 14 template<typename T>
 15 Operation<T>::Operation(T lpa, T rpa)
 16 {
 17     this->lpa = lpa;
 18     this->rpa = rpa;
 19 }
 20 // 加法类
 21 template<typename T>
 22 class AddOperation : public Operation<T>
 23 {
 24 public:
 25     AddOperation(T lpa, T rpa) : Operation<T>(lpa, rpa){}
 26     T getResult()
 27     {
 28         return this->lpa + this->rpa;
 29     }
 30 };
 31 // 减法类
 32 template<typename T>
 33 class SubOperation : public Operation<T>
 34 {
 35 public:
 36     SubOperation(T lpa, T rpa) : Operation<T>(lpa, rpa) {}
 37     T getResult()
 38     {
 39         return this->lpa - this->rpa;
 40     }
 41 };
 42 // 乘法类
 43 template<typename T>
 44 class MulOperation : public Operation<T>
 45 {
 46 public:
 47     MulOperation(T lpa, T rpa) : Operation<T>(lpa, rpa) {}
 48     T getResult()
 49     {
 50         return this->lpa * this->rpa;
 51     }
 52 };
 53 // 除法类
 54 template<typename T>
 55 class DivOperation : public Operation<T>
 56 {
 57 public:
 58     DivOperation(T lpa, T rpa) : Operation<T>(lpa, rpa) {}
 59     T getResult()
 60     {
 61         if (0 == this->rpa)
 62         {
 63             std::cout << "除数不能为0" << std::endl;
 64             return 0;
 65         }
 66         return this->lpa / this->rpa;
 67     }
 68 };
 69 // context类
 70 template<typename T>
 71 class Context
 72 {
 73 public:
 74     Context(Operation<T> * p)
 75     {
 76         m_Operator = p;
 77     }
 78     ~Context()
 79     {
 80         if (nullptr != m_Operator)
 81             delete m_Operator;
 82     }
 83     void getResult()
 84     {
 85         std::cout << m_Operator->getResult() << std::endl;
 86     }
 87 private:
 88     Operation<T> * m_Operator;
 89 };
 90 
 91 // 和简单工厂模式结合
 92 template<typename T>
 93 class Factory
 94 {
 95 public:
 96     Factory(): m_operator(nullptr) {}
 97     ~Factory() {
 98         if (nullptr == m_operator)
 99             delete m_operator;
100         m_operator = nullptr;
101     }
102     static Operation<T> * createObject(T lpa, T rpa, char c);
103 };
104 
105 template<typename T>
106 Operation<T> * Factory<T>::createObject(T lpa, T rpa, char c)
107 {
108     Operation<T> * m_operator;
109     switch (c)
110     {
111     case '+':
112         m_operator = new AddOperation<T>(lpa, rpa);
113         break;
114     case '-':
115         m_operator = new SubOperation<T>(lpa, rpa);
116         break;
117     case '*':
118         m_operator = new MulOperation<T>(lpa, rpa);
119         break;
120     case '/':
121         m_operator = new DivOperation<T>(lpa, rpa);
122     default:
123         m_operator = new AddOperation<T>(lpa, rpa);
124         break;
125     }
126     return m_operator;
127 }

测试代码如下:

 1 #include <iostream>
 2 #include "StrategyModel.h"
 3 
 4 int main()
 5 {
 6     using namespace std;
 7     // 策略模式,和工厂模式结合
 8     Context<double> * p = new Context<double>(Factory<double>::createObject(132.321, 142.32, '+'));
 9     p->getResult();
10     delete p;
11 
12     p = new Context<double>(Factory<double>::createObject(132.321, 142.32, '-'));
13     p->getResult();
14     delete p;
15     
16     p = new Context<double>(Factory<double>::createObject(132.321, 142.32, '*'));
17     p->getResult();
18     delete p;
19 
20     p = new Context<double>(Factory<double>::createObject(132.321, 142.32, '/'));
21     p->getResult();
22     delete p;
23 
24     getchar();
25     return 0;
26 }

其输出结果如下:

  策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以相同的方式调用所有的算法,减少了各种算法类与使用类之间的耦合。策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法种的公共功能。另外一个优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

  当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句。也就是说在基本的策略模式中,选择所具体实现的职责有客户端对象承担了,并转给策略模式的Context对象。

  策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

posted on 2023-07-07 14:01  一杯清酒邀明月  阅读(276)  评论(0编辑  收藏  举报