• 设计模式(一)策略模式


    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 << "
    
    
    
    " << 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 << "
    
    
    
    " << endl;
    33     cout << "----------刘备乐不思蜀了,拆第二个了----------" << endl;
    34     pContext = new CContext(new CGivenGreenLight);
    35     pContext->Operate();
    36     delete pContext;
    37 
    38     cout << "
    
    
    
    " << 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)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端决定。这在一定成都上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

  • 相关阅读:
    node连接数据库(express+mysql)
    Apache与Tomcat有什么关系和区别
    tomcat部署简单的html静态网页
    Vue项目webpack打包部署到服务器
    windows下vue+webpack前端开发环境搭建及nginx部署
    DIV 边框重叠 像素变粗 解决办法
    基于iscroll实现下拉和上拉刷新
    css图片居中(水平居中和垂直居中)
    nodejs分页类
    事件--键盘事件
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/5901773.html
Copyright © 2020-2023  润新知