首页 > 代码库 > 设计模式(一)策略模式

设计模式(一)策略模式

 

 

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

设计模式(一)策略模式