• 设计模式之策略模式


    近期看同事写的代码,看的过程中很是吃力。原因是代码中用了几种设计模式,而我对常用的几种设计模式不熟悉,所以导致看别人调来调去的代码很费劲。正好这几天工作不是特别忙,抓紧时间恶补下相关知识(我看的是《大话设计模式》这本书)。

    今天介绍的是策略模式,分为如下四个部分分析。

    一、什么是策略模式

    策略模式定义了算法家族,分别封装起来,使它们之间可以相互替换,当算法发生变化时,不会影响调用该算法的外部客户。

                    策略模式的UML类图

    二、策略模式用于解决什么问题

    只要在分析问题中发现只要在不同时间应用不同的业务规则,就可以使用策略模式解决这种变化性。

    三、策略模式的优缺点

    优点:

    1. 简化了单元测试,每个算法都有自己的类,可以通过自己的接口单独测试。

    2. 避免使用多重条件判断语句,易于扩展。

    缺点:

    1. 每种具体的策略会增加一个新类,从而会增加系统需要维护的类的数量。

    2. 需要由客户端选择具体实现的对象,并将其转给Strategy。

    四、适用场景

    1. 几个类的大部分算法相同,只有部分逻辑算法有所改动。

    2. 有相似的行为,需要动态的由客户端决定使用哪一种。

    五、举例说明

    以商场打折为例:

    首先给出一个父类和三个子类的具体代码:

     1 //父类
     2 class CashSuper
     3 {
     4 public:
     5     CashSuper(){}
     6     ~CashSuper(){}
     7     virtual double acceptCash(double money);
     8     
     9 };
    10 
    11 double CashSuper::acceptCash(double money)
    12 {
    13     cout<<"CashSuper"<<endl;
    14     return 0.0;
    15 }
    16 
    17 //子类
    18 class CashNormal : public CashSuper
    19 {
    20 public:
    21     CashNormal()
    22     {
    23         cout<<"CashNormal 构造函数.."<<endl;
    24     }
    25     ~CashNormal()
    26     {
    27         cout<<"CashNormal 析构函数.."<<endl;
    28     }
    29     double acceptCash(double money)
    30     {
    31         return money;
    32     }
    33 };
    34 
    35 //子类
    36 class CashRabeta:public CashSuper
    37 {
    38 public:
    39     CashRabeta(double mRabeta)
    40     {
    41         cout<<"CashRabeta 构造函数.."<<endl;
    42         rabeta = mRabeta;
    43     }
    44     ~CashRabeta()
    45     {
    46         cout<<"CashRabeta 析构函数.."<<endl;
    47     }
    48     double acceptCash(double money)
    49     {
    50         return money * rabeta;
    51     }
    52 private:
    53     double rabeta;
    54 };
    55 
    56 //子类
    57 class CashReturn:public CashSuper
    58 {
    59 public:
    60     CashReturn(double mMoneyCondition,double mMoneyReturn)
    61     {
    62         cout<<"CashReturn 构造函数.."<<endl;
    63         moneyCondition = mMoneyCondition;
    64         moneyReturn = mMoneyReturn;
    65     }
    66     ~CashReturn()
    67     {
    68         cout<<"CashReturn 析构函数.."<<endl;
    69     }
    70     double acceptCash(double money)
    71     {
    72         if (money >= moneyCondition)
    73         {
    74             double retain = money - moneyCondition;
    75             double preferent = moneyCondition - moneyReturn;
    76             money = retain + preferent;
    77         }
    78 
    79         return money;
    80     }
    81 private:
    82     double moneyCondition,moneyReturn;
    83 };

    然后给出Context的代码:

     1 class CashContext
     2 {
     3 public:
     4     CashContext(CashSuper *mCS)
     5     {
     6         cs = mCS;
     7     }
     8     ~CashContext()
     9     {
    10         delete cs;
    11     }
    12 
    13     double getResult(double money)
    14     {
    15         if (cs == NULL)
    16         {
    17             cout<<"cs  is NULL"<<endl;
    18         }
    19         return cs->acceptCash(money);
    20     }
    21 private:
    22     CashSuper *cs;
    23     
    24 };

    客户端调用的代码:

     1 int main(int argc, char const *argv[])
     2 {
     3     cout<<"Strategy .."<<endl;
     4 
     5     int type = 2;
     6     double money = 300;
     7 
     8     CashContext *context;
     9     switch(type)
    10     {
    11         case eCashNormal:
    12         context = new CashContext(new CashNormal());
    13         break;
    14         case eCashRabeta:
    15         context = new CashContext(new CashRabeta(0.8));
    16         break;
    17 
    18         case eCashReturn:
    19         context = new CashContext(new CashReturn(300,100));
    20         break;
    21     }
    22     double result = context->getResult(money);
    23 
    24     cout<<"result  :  "<<result<<endl;
    25 
    26     return 0;
    27 }

    从上面可以看出客户端决定了使用哪一种算法的对象,如果增添新的优惠活动时,对应的需要修改客户端的代码,这不能很好的遵循“开闭原则”。

    我们可以将策略模式和简单工厂模式结合使用,代码如下:

     1 //策略模式和简单工厂模式结合
     2 class StrategyFactory
     3 {
     4 public:
     5     StrategyFactory(int type)
     6     {
     7         switch(type)
     8         {
     9             case eCashNormal:
    10             cs = new CashNormal();
    11             break;
    12             case eCashRabeta:
    13             cs = new CashRabeta(0.8);
    14             break;
    15 
    16             case eCashReturn:
    17             cs = new CashReturn(300,100);
    18             break;
    19         }
    20     }
    21     ~StrategyFactory(){
    22         delete cs;
    23     }
    24 
    25     double getResult(double money)
    26     {
    27         cout<<"strategy getResult.."<<endl;
    28         return cs->acceptCash(money);
    29     }
    30 private:
    31     CashSuper *cs;
    32     
    33 };
    34 
    35 int main(int argc, char const *argv[])
    36 {
    37     cout<<"Strategy .."<<endl;
    38 
    39     int type = 2;
    40     double money = 300;
    41 
    42     //策略模式和简单工厂模式结合使用
    43     StrategyFactory *factory = new StrategyFactory(type);
    44     double result = factory->getResult(money);
    45 
    46     cout<<"result  :  "<<result<<endl;
    47 
    48     return 0;
    49 }

    注意:简单工厂模式与策略模式之间的区别很小,都是使用了多态和继承。

    简单工厂模式只是解决了对象的创建问题,而策略模式的目的是确定使用哪种策略。

    举个简单案例:

    简单工厂模式:去餐厅点餐,你点了一份油焖大虾,作为用户,你不需要知道这道菜是用了多少油,多少盐等等,你只需要等上几分钟就可得到一份美味的油焖大虾。

    策略模式:同样去餐厅点了一份油焖大虾,老板让你自己动手去做。这时候就要自己考虑用多少只虾,多少油,多少盐等,该按照怎么的流程做出最终的油焖大虾。

  • 相关阅读:
    总结:python
    Create form:class CreateWindow(Form)
    create sheets: ViewSheet.Create(doc, titleblock.Id)
    create a wall:Wall.Create(doc, line, baseLevel.Id, False)
    creat floor
    excel导入
    Vim正则通配符使用心得
    SVN仓库迁移到Git的完美解决办法
    SVN仓库迁移到Git遇到的两个问题和解决办法
    PGI Compiler for OpenACC Output Syntax Highlighting
  • 原文地址:https://www.cnblogs.com/calence/p/6861411.html
Copyright © 2020-2023  润新知