设计模式之策略模式

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

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

一、什么是策略模式

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

                策略模式的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 }

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

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

举个简单案例:

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

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

原文地址:https://www.cnblogs.com/calence/p/6861411.html