AkiraZheng's Time.

设计模式6:策略模式

Word count: 1.2kReading time: 4 min
2024/02/10

前言

本文中所有设计模式Github代码
其中本文策略模式相关代码在StrategyPattern.h文件中

一、策略模式基础

1. 策略模式的提出

在代码构建过程中,某些对象的算法可能有多种实现(例如不同的排序算法、查找算法等),我们可以根据环境或者条件的不同选择不同的算法来完成任务。
如果将这些算法都封装到对象中,将会使对象变得很复杂,有时候支持不需要的算法也是一种负担
那么如何在运行时根据环境或者条件的不同选择不同的算法来完成任务?

2. 策略模式的设计思想&&代码实现(C++)

2.1 策略模式使用场景示例

假设我们需要实现一个不同国家的税率计算算法,我们需要面对不同国家具有不同税率的问题

2.2 未使用策略模式的代码实现思路

当我们没有采用策略模式时,我们会在一个类中提供不同国家的税率计算算法,然后在main程序中实现不同国家的税率计算算法的调用来实现具体功能

在这种情况下,我们可能会想到通过枚举方法来代表不同的国家,然后在类中通过if-else语句来判断不同国家的税率计算算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 未使用策略模式
#include <iostream>
using namespace std;

enum TexType
{
CN_TAX,
US_TAX,
JP_TAX
};
class SalesOrder
{
TexType type;
public:
double CalculateTax()
{
if (type == CN_TAX)
{
return 0.1;
}
else if (type == US_TAX)
{
return 0.2;
}
else if (type == JP_TAX)
{
return 0.3;
}
}
};

但是很多情况下,业务需求变化是很快的,我们可能随时需要增加对新国家的税率计算算法,这样的话,我们就需要修改SalesOrder类,也要改变枚举值,这样的话,我们就违反了开闭原则,所以我们需要使用策略模式来解决这个问题

策略模式通常还需要结合工厂模式来使用,这样可以更好的解耦

2.3 使用策略模式的代码实现思路

当我们采用策略模式时,我们会在一个类中提供一个抽象的策略类,然后在不同国家的税率计算算法中继承这个抽象的策略类,然后在main程序中实现不同国家的税率计算算法的调用来实现具体功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 使用策略模式
#include <iostream>
using namespace std;

class TaxStrategy
{
public:
virtual double Calculate() = 0;//将税率计算算法抽象为一个虚函数
virtual ~TaxStrategy(){};
};
class CNTax : public TaxStrategy
{
public:
double Calculate()
{
return 0.1;
}
};
class USTax : public TaxStrategy
{
public:
double Calculate()
{
return 0.2;
}
};
class JPTax : public TaxStrategy
{
public:
double Calculate()
{
return 0.3;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class SalesOrder
{
private:
TaxStrategy* strategy;//提供一个抽象的策略类的多态指针
public:
SalesOrder(TaxStrategy* strategy)
{
this->strategy = strategy;
}
double CalculateTax()
{
return strategy->Calculate();
}
~SalesOrder()
{
delete strategy;
}
};
1
2
3
4
5
6
7
int main()
{
SalesOrder* order = new SalesOrder(new CNTax());//new CNTax()这里可以通过工厂模式将其抽象出来
cout << order->CalculateTax() << endl;
delete order;
return 0;
}

在这种情况下,我们只需要添加一个继承自TaxStrategy的新类,不需要修改SalesOrder类,这样就符合了开闭原则

2.4 策略模式结合简单工厂抽象化

在上述代码中,我们可以看到new CNTax()这里可以通过简单工厂方法将其抽象出来,这样可以更好的解耦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TaxStrategyFactory
{
public:
static TaxStrategy* CreateTaxStrategy(TexType type)
{
switch (type)
{
case CN_TAX:
return new CNTax();
case US_TAX:
return new USTax();
case JP_TAX:
return new JPTax();
default:
return nullptr;
}
}
};
1
2
3
4
5
6
7
int main()
{
SalesOrder* order = new SalesOrder(TaxStrategyFactory::CreateTaxStrategy(CN_TAX));
cout << order->CalculateTax() << endl;
delete order;
return 0;
}

这样我们就可以通过工厂模式将new CNTax()这里抽象出来,这样可以更好的解耦,当然TaxStrategyFactory的实现还可以进一步设计成抽象接口,将其改造为工厂方法模式,这里就不再赘述

二、总结

  • 策略模式使得算法可以独立于客户程序(稳定,如SalesOrder)而变化(不稳定、扩展,如CNTax、USTax、JPTax)

  • 策略模式提供一系列可变的算法,客户程序在运行时只需要关心接口,不需要关心算法的内部实现细节

  • 在代码中当出现if-else语句 or switch-case语句时,一般就是需要使用策略模式的时候了(使用策略模式抽象化代替if-else语句 or switch-case语句)(只有在if-else是绝对不变的情况下可以不用将其优化为策略模式,比如一周只有7天,这种确定情况下就不需要优化为策略模式)

CATALOG
  1. 前言
  2. 一、策略模式基础
    1. 1. 策略模式的提出
    2. 2. 策略模式的设计思想&&代码实现(C++)
      1. 2.1 策略模式使用场景示例
      2. 2.2 未使用策略模式的代码实现思路
      3. 2.3 使用策略模式的代码实现思路
      4. 2.4 策略模式结合简单工厂抽象化
  3. 二、总结