设计模式之策略模式
策略模式定义算法家族,分别封装。它们之间可以相互替换,让算法变化,不会影响到用户。优点:适合类中的成员方法为主,算法经常变动;简单了单元测试(因为每个算法都有自己的类,可以通过自己的接口单独测试)。缺点:客户端需要做出判断。
其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对象。
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。