设计模式(一)策略模式

时间:2021-10-18 22:02:15

 

 

1、什么是策略模式?

  策略模式,又叫算法簇模式,就是定义了不同的算法簇,并且之间可以互相替换,此模式算法的变化独立于使用算法的客户。

2、策略模式有什么好处?

  策略模式的好处在于你可以动态改变对象的行为。

3、设计原则

  设计原则是把一个类中经常改变或者将来改变的部分提取出来,作为一个接口(C++中可以用抽象类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现这个接口的类的行为。

  策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口(C++中即为抽象基类)的独立的类中,从而使得他们可以相互替换。策略模式使得算法可以在不影响客户端的情况下发生变化

4、策略模式中有三个对象:

  (1)环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。

  (2)抽象策略对象:它可由接口或者抽象类来实现。

  (3)具体策略对象:它封装了实现不同功能的不同算法。

5、适用性

  当存在以下情况时,使用策略模式

  (1)“策略”提供一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种。

  (2)需要使用一个算法的不同变体。例如,你可能会定义一些反应不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。

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

  (4)一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入他们各自的Strategy类中以代替这些条件语句。

 

6、结构

  设计模式(一)策略模式

 

7、应用场景举例:

  刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。

  先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。

  先来看看图。

  设计模式(一)策略模式

 

  解释:

  main(),赵云

  CContext,锦囊

  CStrategy,策略抽象类

  CBackDoor,策略之一

  CGivenGreenLight,策略之二

  CBlockEnemy,策略之三

  说明:一个策略放到一个锦囊里。当用的时候,找到这个锦囊,从锦囊里拿出策略来使用。

  注意:锦囊只是简单的装载和调用策略,锦囊里没有逻辑。策略会有更大的自主权,运行更多的逻辑

 

  代码:

  三个策略继承自抽象类CStrategy,首先是CStrategy类的定义:

1 #ifndef    _STRATEGY_H_
2 #define    _STRATEGY_H_
3 class CStrategy{
4 public:
5     CStrategy(void){};
6     virtual ~CStrategy(void){};
7     virtual void Operate(void) = 0;//纯虚函数,这样每个继承自CStrategy的类都可以实现一个自身的Operate()函数,即实现各自的策略
8 };
9 #endif

  然后再写三个实现类,因为有三个策略:

  妙计一:初到吴国:

  BackDoor.h

 1 #ifndef        _BACKDOOR_H_
 2 #define        _BACKDOOR_H_
 3 #include "Strategy.h"
 4 class CBackDoor :public CStrategy{
 5 public:
 6     CBackDoor(void);
 7     ~CBackDoor(void);
 8     void Operate(void);
 9 };
10 #endif

  BackDoor.cpp

 1 #include "BackDoor.h"
 2 #include <iostream>
 3 using namespace std;
 4 //构造函数
 5 CBackDoor::CBackDoor(void)
 6 {
 7     
 8 }
 9 
10 //析构函数
11 CBackDoor::~CBackDoor(void)
12 {
13     
14 }
15 
16 void CBackDoor::Operate(void)
17 {
18     cout << "找乔国老帮忙,让吴国太给孙权施压" << endl;
19 }

  

  妙计二:求吴国太开绿灯,放行:

  GivenGreenLight.h

 1 #ifndef        _GIVENGREENLIGHT_H_
 2 #define        _GIVENGREENLIGHT_H_
 3 #include "Strategy.h"
 4 
 5 class CGivenGreenLight:public CStrategy{
 6 public:
 7     CGivenGreenLight(void);
 8     ~CGivenGreenLight(void);
 9     void Operate(void);
10 };
11 #endif

  GivenGreenLight.cpp

 1 #include "GivenGreenLight.h"
 2 #include <iostream>
 3 using namespace std;
 4 
 5 CGivenGreenLight::CGivenGreenLight(void)
 6 {
 7 
 8 }
 9 
10 CGivenGreenLight::~CGivenGreenLight(void)
11 {
12 
13 }
14 
15 void CGivenGreenLight::Operate(void)
16 {
17     cout << "求吴国太开个绿灯,放行!" << endl;
18 }

 

  妙计三:孙夫人断后,挡住追兵:

  BlockEnemy.h

 1 #ifndef        _BLOCKENEMY_H_
 2 #define        _BLOCKENEMY_H_
 3 #include "Strategy.h"
 4 class CBlockEnemy :public CStrategy{
 5 public:
 6     CBlockEnemy(void);
 7     ~CBlockEnemy(void);
 8     void Operate(void);
 9 
10 };
11 #endif

  BlockEnemy.cpp

 1 #include "BlockEnemy.h"
 2 #include <iostream>
 3 using namespace std;
 4 
 5 CBlockEnemy::CBlockEnemy(void)
 6 {
 7 
 8 }
 9 
10 CBlockEnemy::~CBlockEnemy(void)
11 {
12 
13 }
14 
15 void CBlockEnemy::Operate(void)
16 {
17     cout << "孙夫人断后,挡住追兵" << endl;
18 }

 

  好了,三个妙计是有了,还需要一个地方放妙计,即锦囊:

  Context.h

 1 #ifndef        _CONTEXT_H_
 2 #define        _CONTEXT_H_
 3 #include "Strategy.h"
 4 //定义环境(锦囊)存策略
 5 class CContext{
 6 public:
 7     CContext(CStrategy* pStrategy);
 8     ~CContext(void);
 9     void Operate(void);
10 private:
11     CStrategy* m_pStrategy;
12 };
13 #endif

  Context.cpp

 1 #include "Context.h"
 2 //构造函数中传入具体的策略,使用抽象基类CStrategy指针类型
 3 //指向策略
 4 //CStrategy中的Operate()函数定义为纯虚函数,如此可实现多态:在不同的类中使用不同的operate()函数
 5 CContext::CContext(CStrategy* pStrategy)
 6 {
 7     this->m_pStrategy = pStrategy;
 8 }
 9 //析构函数
10 CContext::~CContext(void)
11 {
12     delete this->m_pStrategy;    //销毁CStrategy类指针
13 }
14 
15 //操作具体的策略
16 void CContext::Operate(void)
17 {
18     this->m_pStrategy->Operate();
19 }

  然后就是赵云护送刘备去娶亲了。看看执行过程吧。

  excute.cpp

 1 #include <iostream>
 2 #include <tchar.h>
 3 #include "Context.h"
 4 #include "BackDoor.h"
 5 #include "GivenGreenLight.h"
 6 #include "BlockEnemy.h"
 7 using namespace std;
 8 
 9 int _tmain(int argc, _TCHAR** argv)
10 {
11     //定义一个CContext类的指针
12     CContext* pContext;
13 
14     cout << "\n\n\n\n" << endl;
15     cout << "----------刚刚到吴国的时候拆第一个----------" << endl;
16     //使用关键字new在堆上动态创建一个对象
17     /*
18     它实际上做了三件事:
19     获得一块内存空间
20     调用构造函数
21     返回正确的指针。
22     */
23     pContext = new CContext(new CBackDoor);
24     pContext->Operate();
25     /*
26     delete时做了两件事:
27     1、调用 pContext指向对象的析构函数,对打开的文件进行关闭。
28     2、释放该对象的内存
29     */
30     delete pContext;
31 
32     cout << "\n\n\n\n" << endl;
33     cout << "----------刘备乐不思蜀了,拆第二个了----------" << endl;
34     pContext = new CContext(new CGivenGreenLight);
35     pContext->Operate();
36     delete pContext;
37 
38     cout << "\n\n\n\n" << endl;
39     cout << "----------孙权的小兵追了,咋办?拆第三个----------" << endl;
40     pContext = new CContext(new CBlockEnemy);
41     pContext->Operate();
42     delete pContext;
43 
44     /*
45     _CrtSetDbgFlag:
46         检索或修改 _crtDbgFlag 标志的状态,以控制调试堆管理器的分配行为
47     _CRTDBG_ALLOC_MEM_DF:
48         启用调试堆分配并使用内存块类型标识符,例如 _CLIENT_BLOCK。
49     _CRTDBG_LEAK_CHECK_DF:
50         在程序退出时通过对 _CrtDumpMemoryLeaks 的调用执行自动泄露检查,如果应用程序无法释放它分配的所有内存,则生成错误报告。
51     */
52     _CrtSetDbgFlag(-_CRTDBG_ALLOC_MEM_DF || _CRTDBG_LEAK_CHECK_DF);
53     _CrtDumpMemoryLeaks();
54     getchar();
55     return 0;
56 
57 }

  运行结果:

  设计模式(一)策略模式

 

 8、总结与分析

  (1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得他们可以互换。”

  (2)在策略模式中,应该由客户端自己决定在什么情况下使用什么具体策略。

  (3)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端决定。这在一定成都上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。